generating policies first version.
Still includes linkerd ports.
This commit is contained in:
		
							parent
							
								
									496e58347c
								
							
						
					
					
						commit
						108f21ea58
					
				| @ -240,6 +240,11 @@ func LoadConfig(file string) (*Config, error) { | |||||||
| 	for _, ns := range config.Namespaces { | 	for _, ns := range config.Namespaces { | ||||||
| 		for _, app := range ns.Applications { | 		for _, app := range ns.Applications { | ||||||
| 			app.Namespace = ns | 			app.Namespace = ns | ||||||
|  | 			for i, _ := range app.Ports { | ||||||
|  | 				if app.Ports[i].Protocol == "" { | ||||||
|  | 					app.Ports[i].Protocol = "TCP" | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -4,7 +4,6 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"iter" | 	"iter" | ||||||
| 	"k8s.io/api/core/v1" | 	"k8s.io/api/core/v1" | ||||||
| 	"maps" |  | ||||||
| 	"os" | 	"os" | ||||||
| 	"slices" | 	"slices" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| @ -35,13 +34,6 @@ func IterToSlice[K any](i iter.Seq[K]) []K { | |||||||
| 	return res | 	return res | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func MapKeys[K comparable, V any](m map[K]V) []K { |  | ||||||
| 	return IterToSlice(maps.Keys(m)) |  | ||||||
| } |  | ||||||
| func MapValues[K comparable, V any](m map[K]V) []V { |  | ||||||
| 	return IterToSlice(maps.Values(m)) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func validate(files []string, options *Options) error { | func validate(files []string, options *Options) error { | ||||||
| 	clientset, _ := GetKubernetesConnection() | 	clientset, _ := GetKubernetesConnection() | ||||||
| 	config, err := readConfig(files) | 	config, err := readConfig(files) | ||||||
|  | |||||||
| @ -6,9 +6,10 @@ import ( | |||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type Generator interface { | type Generator interface { | ||||||
| 	Init(write io.Writer) error | 	Init(writer io.Writer) error | ||||||
| 	GenerateNamespace(writer io.Writer, namespace *Namespace) error | 	GenerateNamespace(writer io.Writer, namespace *Namespace) error | ||||||
| 	GenerateCommunicationRule(writer io.Writer, app *Application, ingress *Ingress, egress *Egress) error | 	GenerateCommunicationRule(writer io.Writer, app *Application, ingress *Ingress, egress *Egress) error | ||||||
|  | 	Finalize(writer io.Writer) error | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type ApplicationPeer struct { | type ApplicationPeer struct { | ||||||
| @ -172,5 +173,5 @@ func Generate(writer io.Writer, generator Generator, config *Config) error { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return nil | 	return generator.Finalize(writer) | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,71 +4,154 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io" | 	"io" | ||||||
| 	"os" | 	"os" | ||||||
|  | 	"slices" | ||||||
|  | 	"strconv" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type LinkerdPolicyGenerator struct { | type LinkerdPolicyGenerator struct { | ||||||
| 	config          *Config | 	config          *Config | ||||||
| 	policyTemplates *PolicyTemplates | 	policyTemplates *PolicyTemplates | ||||||
|  | 
 | ||||||
|  | 	networks map[string]*Network | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (g LinkerdPolicyGenerator) Init(writer io.Writer) error { | func NewLinkerdPolicyGenerator(config *Config, templates *PolicyTemplates) *LinkerdPolicyGenerator { | ||||||
| 	// start by generating network authentications
 | 	return &LinkerdPolicyGenerator{ | ||||||
| 	for _, network := range g.config.Networks { | 		config:          config, | ||||||
| 		fmt.Fprintf(os.Stderr, "NetworkAuthentication default/%s\n", network.Name) | 		policyTemplates: templates, | ||||||
| 		template := g.policyTemplates.PredefineApplicationPolicyTemplate("linkerd", "networkauthentication") | 		networks:        make(map[string]*Network), | ||||||
| 		if template == nil { |  | ||||||
| 			return fmt.Errorf("Linkerd template for network authentication not found") |  | ||||||
| 		} |  | ||||||
| 		err := template.Execute(writer, network) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return fmt.Errorf("Error executing network authentication template for %s", network.Name) |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (g *LinkerdPolicyGenerator) Init(writer io.Writer) error { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (g LinkerdPolicyGenerator) GenerateNamespace(writer io.Writer, namespace *Namespace) error { | func (g *LinkerdPolicyGenerator) GenerateNamespace(writer io.Writer, namespace *Namespace) error { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (g LinkerdPolicyGenerator) GenerateCommunicationRule( | func (g *LinkerdPolicyGenerator) GenerateCommunicationRule( | ||||||
| 	writer io.Writer, | 	writer io.Writer, | ||||||
| 	app *Application, | 	app *Application, | ||||||
| 	ingress *Ingress, | 	ingress *Ingress, | ||||||
| 	egress *Egress) error { | 	egress *Egress) error { | ||||||
| 
 | 
 | ||||||
| 	// and then the meshTLSAuthentications
 | 	if app.Namespace.Unauthorized { | ||||||
| 	fmt.Fprintf(os.Stderr, "MeshTLSAuthentication %s/%s %v\n", | 		fmt.Fprintf(os.Stderr, "UNAUTHORIZED %s\n", app.Name) | ||||||
| 		app.Namespace.Name, app.Name, app.ServiceAccounts) | 		return nil | ||||||
| 	template := g.policyTemplates.PredefineApplicationPolicyTemplate("linkerd", "meshtlsauthentication") |  | ||||||
| 	if template == nil { |  | ||||||
| 		return fmt.Errorf("Could not find meshtlsauthentication template") |  | ||||||
| 	} |  | ||||||
| 	err := template.Execute(writer, app) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// and the server resources
 | 	// and the server resources
 | ||||||
| 	fmt.Fprintf(os.Stderr, "Server %s/%s\n", | 	fmt.Fprintf(os.Stderr, "Server %s/%s\n", | ||||||
| 		app.Namespace.Name, app.Name) | 		app.Namespace.Name, app.Name) | ||||||
| 	template = g.policyTemplates.PredefineApplicationPolicyTemplate("linkerd", "server") | 	err := g.policyTemplates.Execute("linkerd", "server", writer, app) | ||||||
| 	if template == nil { |  | ||||||
| 		return fmt.Errorf("Could not find meshtlsauthentication template") |  | ||||||
| 	} |  | ||||||
| 	err = template.Execute(writer, app) |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if len(ingress.Applications)+ | 	if len(ingress.Applications)+ | ||||||
| 		len(ingress.Networks)+ | 		len(ingress.Networks) > 0 { | ||||||
| 		len(egress.Applications)+ | 		ports := make(map[int]bool) | ||||||
| 		len(egress.Networks) > 0 { | 		//
 | ||||||
| 		// non-trivial regular network policy
 | 		clientApplications := make(map[int][]*ApplicationPeer) | ||||||
|  | 		for _, ingress := range ingress.Applications { | ||||||
|  | 			for _, port := range ingress.Ports { | ||||||
|  | 				if port.Protocol == "TCP" { | ||||||
|  | 					portno, err := strconv.Atoi(port.Port) | ||||||
|  | 					if err != nil { | ||||||
|  | 						return fmt.Errorf("Error convert port '%s' of ingress '%s' of app '%s': %w", | ||||||
|  | 							port.Port, ingress.Application.Name, app.Name, err) | ||||||
|  | 					} | ||||||
|  | 					ports[portno] = true | ||||||
|  | 					clientApplications[portno] = append(clientApplications[portno], ingress) | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		// TODO
 | 		clientNetworks := make(map[int][]*NetworkPeer) | ||||||
|  | 		for _, ingress := range ingress.Networks { | ||||||
|  | 			for _, port := range ingress.Ports { | ||||||
|  | 				if port.Protocol == "TCP" { | ||||||
|  | 					portno, err := strconv.Atoi(port.Port) | ||||||
|  | 					if err != nil { | ||||||
|  | 						return fmt.Errorf("Error convert port '%s' of ingress '%s' of app '%s': %w", | ||||||
|  | 							port.Port, ingress.Network.Name, app.Name, err) | ||||||
|  | 					} | ||||||
|  | 					ports[portno] = true | ||||||
|  | 					clientNetworks[portno] = append(clientNetworks[portno], ingress) | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		for port, _ := range ports { | ||||||
|  | 			fmt.Fprintf(os.Stderr, "Generating authorization policy: %v %v -> %v : %v\n", | ||||||
|  | 				Map(clientApplications[port], func(peer *ApplicationPeer) string { | ||||||
|  | 					return peer.Application.Name | ||||||
|  | 				}), | ||||||
|  | 				Map(clientNetworks[port], func(peer *NetworkPeer) string { | ||||||
|  | 					return peer.Network.Name | ||||||
|  | 				}), | ||||||
|  | 				app.Name, | ||||||
|  | 				port) | ||||||
|  | 			// Optimization: keep track of the references clientApps and
 | ||||||
|  | 			// client Networks and only generate authentications for those instead of for
 | ||||||
|  | 			// all apps and networks.
 | ||||||
|  | 			for _, clientNetwork := range clientNetworks[port] { | ||||||
|  | 				g.networks[clientNetwork.Network.Name] = clientNetwork.Network | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			// linkerd rules
 | ||||||
|  | 			// 1. an authpolicy may contain only one meshtlsauthentication rule
 | ||||||
|  | 			// 2. an authpolicy may contain only one service account .
 | ||||||
|  | 			// 3. an authpolicy may contain more than one networkauthentication
 | ||||||
|  | 			//
 | ||||||
|  | 			// Should generate here a methtlsautheorization for every port
 | ||||||
|  | 			// and pass in a list of service accounts instead of a list of apps.
 | ||||||
|  | 			serviceAccounts := g.serviceAccounts(clientApplications[port]) | ||||||
|  | 			if len(serviceAccounts) > 0 { | ||||||
|  | 				err = g.policyTemplates.Execute("linkerd", "meshtlsauthentication", | ||||||
|  | 					writer, | ||||||
|  | 					map[string]any{ | ||||||
|  | 						"app":             app, | ||||||
|  | 						"port":            port, | ||||||
|  | 						"serviceAccounts": serviceAccounts, | ||||||
|  | 					}) | ||||||
|  | 				if err != nil { | ||||||
|  | 					return err | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			err = g.policyTemplates.Execute("linkerd", "authorizationpolicy", | ||||||
|  | 				writer, | ||||||
|  | 				map[string]any{ | ||||||
|  | 					"app":            app, | ||||||
|  | 					"port":           port, | ||||||
|  | 					"clientNetworks": clientNetworks[port], | ||||||
|  | 				}) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (g *LinkerdPolicyGenerator) serviceAccounts(peers []*ApplicationPeer) []string { | ||||||
|  | 	serviceAccounts := []string{} | ||||||
|  | 	for _, peer := range peers { | ||||||
|  | 		serviceAccounts = append(serviceAccounts, peer.Application.ServiceAccounts...) | ||||||
|  | 	} | ||||||
|  | 	slices.Sort(serviceAccounts) | ||||||
|  | 	return slices.Compact(serviceAccounts) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (g *LinkerdPolicyGenerator) Finalize(writer io.Writer) error { | ||||||
|  | 	for _, network := range g.networks { | ||||||
|  | 		fmt.Fprintf(os.Stderr, "NetworkAuthentication default/%s\n", network.Name) | ||||||
|  | 		err := g.policyTemplates.Execute("linkerd", "networkauthentication", writer, network) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  | |||||||
| @ -42,10 +42,7 @@ func generateNetworkPolicy(files []string, options *Options) error { | |||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	var generator Generator | 	var generator Generator | ||||||
| 	generator = NetworkPolicyGenerator{ | 	generator = NewNetworkPolicyGenerator(config, policyTemplates) | ||||||
| 		config:          config, |  | ||||||
| 		policyTemplates: policyTemplates, |  | ||||||
| 	} |  | ||||||
| 	err = Generate(os.Stdout, generator, config) | 	err = Generate(os.Stdout, generator, config) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| @ -74,10 +71,7 @@ func generateLinkerdPolicies(files []string, options *Options) error { | |||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	var generator Generator | 	var generator Generator | ||||||
| 	generator = LinkerdPolicyGenerator{ | 	generator = NewLinkerdPolicyGenerator(config, policyTemplates) | ||||||
| 		config:          config, |  | ||||||
| 		policyTemplates: policyTemplates, |  | ||||||
| 	} |  | ||||||
| 	err = Generate(os.Stdout, generator, config) | 	err = Generate(os.Stdout, generator, config) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
|  | |||||||
| @ -12,11 +12,18 @@ type NetworkPolicyGenerator struct { | |||||||
| 	policyTemplates *PolicyTemplates | 	policyTemplates *PolicyTemplates | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (g NetworkPolicyGenerator) Init(writer io.Writer) error { | func NewNetworkPolicyGenerator(config *Config, templates *PolicyTemplates) *NetworkPolicyGenerator { | ||||||
|  | 	return &NetworkPolicyGenerator{ | ||||||
|  | 		config:          config, | ||||||
|  | 		policyTemplates: templates, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (g *NetworkPolicyGenerator) Init(writer io.Writer) error { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (g NetworkPolicyGenerator) GenerateNamespace(writer io.Writer, namespace *Namespace) error { | func (g *NetworkPolicyGenerator) GenerateNamespace(writer io.Writer, namespace *Namespace) error { | ||||||
| 	fmt.Fprintf(os.Stderr, "Namespace %s\n", namespace.Name) | 	fmt.Fprintf(os.Stderr, "Namespace %s\n", namespace.Name) | ||||||
| 
 | 
 | ||||||
| 	templates := g.policyTemplates.NamespaceTemplates("netpol", namespace.Capabilities) | 	templates := g.policyTemplates.NamespaceTemplates("netpol", namespace.Capabilities) | ||||||
| @ -30,7 +37,7 @@ func (g NetworkPolicyGenerator) GenerateNamespace(writer io.Writer, namespace *N | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (g NetworkPolicyGenerator) GenerateCommunicationRule( | func (g *NetworkPolicyGenerator) GenerateCommunicationRule( | ||||||
| 	writer io.Writer, | 	writer io.Writer, | ||||||
| 	app *Application, | 	app *Application, | ||||||
| 	ingress *Ingress, | 	ingress *Ingress, | ||||||
| @ -42,11 +49,7 @@ func (g NetworkPolicyGenerator) GenerateCommunicationRule( | |||||||
| 		len(egress.Networks) > 0 { | 		len(egress.Networks) > 0 { | ||||||
| 		// non-trivial regular network policy
 | 		// non-trivial regular network policy
 | ||||||
| 
 | 
 | ||||||
| 		tmpl := g.policyTemplates.ApplicationTemplate("netpol") | 		err := g.policyTemplates.Execute("netpol", "pod", writer, map[string]any{ | ||||||
| 		if tmpl == nil { |  | ||||||
| 			return fmt.Errorf("Could not find policy template for 'netpol'") |  | ||||||
| 		} |  | ||||||
| 		err := tmpl.Execute(writer, map[string]any{ |  | ||||||
| 			"app":     app, | 			"app":     app, | ||||||
| 			"ingress": ingress, | 			"ingress": ingress, | ||||||
| 			"egress":  egress, | 			"egress":  egress, | ||||||
| @ -68,18 +71,15 @@ func (g NetworkPolicyGenerator) GenerateCommunicationRule( | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for predefined, _ := range allPredefined { | 	for predefined, _ := range allPredefined { | ||||||
| 		tmpl := g.policyTemplates.PredefineApplicationPolicyTemplate("netpol", predefined) | 		err := g.policyTemplates.Execute("netpol", predefined, | ||||||
| 		if tmpl == nil { | 			writer, map[string]any{ | ||||||
| 			return fmt.Errorf("Could not find predefined template for netpol/%s", predefined) | 				"app":     app, | ||||||
| 		} | 				"ingress": slices.Contains(ingress.Predefined, predefined), | ||||||
| 		err := tmpl.Execute(writer, map[string]any{ | 				"egress":  slices.Contains(egress.Predefined, predefined), | ||||||
| 			"app":     app, | 				"labels": map[string]string{ | ||||||
| 			"ingress": slices.Contains(ingress.Predefined, predefined), | 					"policy-generator": "1", | ||||||
| 			"egress":  slices.Contains(egress.Predefined, predefined), | 				}, | ||||||
| 			"labels": map[string]string{ | 			}) | ||||||
| 				"policy-generator": "1", |  | ||||||
| 			}, |  | ||||||
| 		}) |  | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| @ -87,3 +87,7 @@ func (g NetworkPolicyGenerator) GenerateCommunicationRule( | |||||||
| 
 | 
 | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func (g *NetworkPolicyGenerator) Finalize(writer io.Writer) error { | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ package main | |||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"io" | ||||||
| 	"io/fs" | 	"io/fs" | ||||||
| 	"log" | 	"log" | ||||||
| 	"os" | 	"os" | ||||||
| @ -119,12 +120,21 @@ func (t *PolicyTemplates) NamespaceTemplates(policyType string, capabilities []s | |||||||
| 	return res | 	return res | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (t *PolicyTemplates) ApplicationTemplate(policyType string) *template.Template { |  | ||||||
| 	tmpl := t.templates.Lookup(fmt.Sprintf("templates/%s/application/pod.yaml", policyType)) |  | ||||||
| 	return tmpl |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (t *PolicyTemplates) PredefineApplicationPolicyTemplate(policyType string, predefined string) *template.Template { | func (t *PolicyTemplates) PredefineApplicationPolicyTemplate(policyType string, predefined string) *template.Template { | ||||||
| 	tmpl := t.templates.Lookup(fmt.Sprintf("templates/%s/application/%s.yaml", policyType, predefined)) | 	tmpl := t.templates.Lookup(fmt.Sprintf("templates/%s/application/%s.yaml", policyType, predefined)) | ||||||
| 	return tmpl | 	return tmpl | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func (t *PolicyTemplates) Execute(policyType string, predefined string, writer io.Writer, data any) error { | ||||||
|  | 	tmpl := t.PredefineApplicationPolicyTemplate(policyType, predefined) | ||||||
|  | 	if tmpl == nil { | ||||||
|  | 		return fmt.Errorf("Could not find template %s for policy type %s", predefined, policyType) | ||||||
|  | 	} | ||||||
|  | 	err := tmpl.Execute(writer, data) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("Error rendering template %s for policy type %s: %w", predefined, policyType, err) | ||||||
|  | 	} | ||||||
|  | 	writer.Write([]byte("\n")) | ||||||
|  | 	return nil | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | |||||||
| @ -0,0 +1,22 @@ | |||||||
|  | --- | ||||||
|  | apiVersion: policy.linkerd.io/v1alpha1 | ||||||
|  | kind: AuthorizationPolicy | ||||||
|  | metadata: | ||||||
|  |   name: {{ .app.Name }}-p{{ .port }} | ||||||
|  |   namespace: {{ .app.Namespace.Name}} | ||||||
|  | spec: | ||||||
|  |   targetRef: | ||||||
|  |     group: policy.linkerd.io | ||||||
|  |     kind: Server | ||||||
|  |     name: {{ .app.Name }}-p{{ .port }} | ||||||
|  |   requiredAuthenticationRefs: | ||||||
|  |     - name: {{ .app.Name }}-p{{ .port }} | ||||||
|  |       namespace: {{ .app.Namespace.Name }} | ||||||
|  |       kind: MeshTLSAuthentication | ||||||
|  |       group: policy.linkerd.io | ||||||
|  |   {{- range $net := .clientNetworks }} | ||||||
|  |     - name: {{ $net.Network.Name }} | ||||||
|  |       namespace: default | ||||||
|  |       kind: NetworkAuthentication | ||||||
|  |       group: policy.linkerd.io | ||||||
|  |   {{- end }} | ||||||
| @ -2,16 +2,12 @@ | |||||||
| apiVersion: policy.linkerd.io/v1alpha1 | apiVersion: policy.linkerd.io/v1alpha1 | ||||||
| kind: MeshTLSAuthentication | kind: MeshTLSAuthentication | ||||||
| metadata: | metadata: | ||||||
|   name: {{ .Name }} |   name: {{ .app.Name }}-{{.port}} | ||||||
|   namespace: {{ .Namespace.Name }} |   namespace: {{ .app.Namespace.Name }} | ||||||
| spec: | spec: | ||||||
|   {{- if .ServiceAccounts }} |  | ||||||
|   identityRefs: |   identityRefs: | ||||||
|   {{- range $sa := .ServiceAccounts }} |   {{- range $sa := .serviceAccounts }} | ||||||
|     - kind: ServiceAccount |     - kind: ServiceAccount | ||||||
|       name: {{ $sa }} |       name: {{ $sa }} | ||||||
|   {{- end }} |   {{- end }} | ||||||
|   {{- else }} |  | ||||||
|     fail (printf "no service accounts defined for app %s" .Name ) |  | ||||||
|   {{- end}} |  | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										17
									
								
								cmd/policygen/util.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								cmd/policygen/util.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | package main | ||||||
|  | 
 | ||||||
|  | import "maps" | ||||||
|  | 
 | ||||||
|  | func MapKeys[K comparable, V any](m map[K]V) []K { | ||||||
|  | 	return IterToSlice(maps.Keys(m)) | ||||||
|  | } | ||||||
|  | func MapValues[K comparable, V any](m map[K]V) []V { | ||||||
|  | 	return IterToSlice(maps.Values(m)) | ||||||
|  | } | ||||||
|  | func Map[K any, V any](s []K, mapper func(K) V) []V { | ||||||
|  | 	res := make([]V, len(s)) | ||||||
|  | 	for i, _ := range s { | ||||||
|  | 		res[i] = mapper(s[i]) | ||||||
|  | 	} | ||||||
|  | 	return res | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user