From 2bea96cc57ac8d8457dcc43a23a59acce06312d0 Mon Sep 17 00:00:00 2001 From: Erik Brakkee Date: Sat, 25 Jan 2025 14:49:33 +0100 Subject: [PATCH] eliminating duplicate communications. this caused problems with linkerd and helm --- cmd/policygen/generator.go | 23 +++- cmd/policygen/linkerd_generator.go | 114 ++++++------------ .../application/authorizationpolicy-app.yaml | 16 +++ ...licy.yaml => authorizationpolicy-net.yaml} | 12 +- .../application/meshtlsauthentication.yaml | 13 +- 5 files changed, 84 insertions(+), 94 deletions(-) create mode 100644 cmd/policygen/templates/linkerd/application/authorizationpolicy-app.yaml rename cmd/policygen/templates/linkerd/application/{authorizationpolicy.yaml => authorizationpolicy-net.yaml} (50%) diff --git a/cmd/policygen/generator.go b/cmd/policygen/generator.go index fa4c329..f9df019 100644 --- a/cmd/policygen/generator.go +++ b/cmd/policygen/generator.go @@ -3,6 +3,7 @@ package main import ( "io" "os" + "slices" ) type Generator interface { @@ -15,13 +16,15 @@ type Generator interface { type ApplicationPeer struct { Application *Application Ports []Port - Rule string + // used as convenience for template rendering. + Rule string } type NetworkPeer struct { Network *Network Ports []Port - Rule string + // Used as convenience for template rendering. + Rule string } type Peer struct { @@ -32,13 +35,23 @@ type Peer struct { func (p *Peer) append(app *ApplicationPeer, network *NetworkPeer, predefined string) { if app != nil { - p.Applications = append(p.Applications, app) + if !slices.ContainsFunc(p.Applications, func(a *ApplicationPeer) bool { + return a.Application.Name == app.Application.Name && slices.Equal(a.Ports, app.Ports) + }) { + p.Applications = append(p.Applications, app) + } } if network != nil { - p.Networks = append(p.Networks, network) + if !slices.ContainsFunc(p.Networks, func(n *NetworkPeer) bool { + return n.Network.Name == network.Network.Name && slices.Equal(n.Network.Ports, network.Network.Ports) + }) { + p.Networks = append(p.Networks, network) + } } if predefined != "" { - p.Predefined = append(p.Predefined, predefined) + if !slices.Contains(p.Predefined, predefined) { + p.Predefined = append(p.Predefined, predefined) + } } } diff --git a/cmd/policygen/linkerd_generator.go b/cmd/policygen/linkerd_generator.go index 183d780..1a57b8a 100644 --- a/cmd/policygen/linkerd_generator.go +++ b/cmd/policygen/linkerd_generator.go @@ -7,7 +7,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "os" "slices" - "strconv" "strings" ) @@ -15,6 +14,7 @@ type LinkerdPolicyGenerator struct { config *Config policyTemplates *PolicyTemplates + apps map[string]*Application networks map[string]*Network } @@ -22,6 +22,7 @@ func NewLinkerdPolicyGenerator(config *Config, templates *PolicyTemplates) *Link return &LinkerdPolicyGenerator{ config: config, policyTemplates: templates, + apps: make(map[string]*Application), networks: make(map[string]*Network), } } @@ -53,83 +54,37 @@ func (g *LinkerdPolicyGenerator) GenerateCommunicationRule( return err } - if len(ingress.Applications)+ - len(ingress.Networks) > 0 { - ports := make(map[int]bool) - // - 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) - } + for _, ingress := range ingress.Applications { + for _, port := range ingress.Ports { + if port.Protocol != "TCP" { + continue } - } - - 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 only 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", + g.apps[ingress.Application.Name] = ingress.Application + err = g.policyTemplates.Execute("linkerd", "authorizationpolicy-app", writer, map[string]any{ - "app": app, - "port": port, - "clientNetworks": clientNetworks[port], + "app": app, + "port": port.Port, + "client": ingress.Application, + }) + if err != nil { + return err + } + } + } + + for _, ingress := range ingress.Networks { + for _, port := range ingress.Ports { + if port.Protocol != "TCP" { + continue + } + g.networks[ingress.Network.Name] = ingress.Network + err = g.policyTemplates.Execute("linkerd", "authorizationpolicy-net", + writer, + map[string]any{ + "app": app, + "port": port.Port, + "client": ingress.Network, }) if err != nil { return err @@ -160,6 +115,15 @@ func (g *LinkerdPolicyGenerator) serviceAccounts(peers []*ApplicationPeer) []v1. } func (g *LinkerdPolicyGenerator) Finalize(writer io.Writer) error { + for _, app := range g.apps { + fmt.Fprintf(os.Stderr, "MeshTLSAuthentication %s/%s %v\n", + app.Namespace.Name, app.Name, app.ServiceAccounts) + err := g.policyTemplates.Execute("linkerd", "meshtlsauthentication", + writer, app) + if err != nil { + return err + } + } for _, network := range g.networks { fmt.Fprintf(os.Stderr, "NetworkAuthentication default/%s\n", network.Name) err := g.policyTemplates.Execute("linkerd", "networkauthentication", writer, network) diff --git a/cmd/policygen/templates/linkerd/application/authorizationpolicy-app.yaml b/cmd/policygen/templates/linkerd/application/authorizationpolicy-app.yaml new file mode 100644 index 0000000..778b6a3 --- /dev/null +++ b/cmd/policygen/templates/linkerd/application/authorizationpolicy-app.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: policy.linkerd.io/v1alpha1 +kind: AuthorizationPolicy +metadata: + name: app-{{ .client.Name }}-to-{{ .app.Name }}-p{{ .port }} + namespace: {{ .app.Namespace.Name}} +spec: + targetRef: + group: policy.linkerd.io + kind: Server + name: {{ .app.Name }}-p{{ .port }} + requiredAuthenticationRefs: + - name: {{ .client.Name }} + namespace: {{ .client.Namespace.Name }} + kind: MeshTLSAuthentication + group: policy.linkerd.io \ No newline at end of file diff --git a/cmd/policygen/templates/linkerd/application/authorizationpolicy.yaml b/cmd/policygen/templates/linkerd/application/authorizationpolicy-net.yaml similarity index 50% rename from cmd/policygen/templates/linkerd/application/authorizationpolicy.yaml rename to cmd/policygen/templates/linkerd/application/authorizationpolicy-net.yaml index 1059cc4..a5f0d0a 100644 --- a/cmd/policygen/templates/linkerd/application/authorizationpolicy.yaml +++ b/cmd/policygen/templates/linkerd/application/authorizationpolicy-net.yaml @@ -2,7 +2,7 @@ apiVersion: policy.linkerd.io/v1alpha1 kind: AuthorizationPolicy metadata: - name: {{ .app.Name }}-p{{ .port }} + name: net-{{ .client.Name }}-to-{{ .app.Name }}-p{{ .port }} namespace: {{ .app.Namespace.Name}} spec: targetRef: @@ -10,13 +10,7 @@ spec: 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 }} + - name: {{ .client.Name }} namespace: default kind: NetworkAuthentication - group: policy.linkerd.io - {{- end }} \ No newline at end of file + group: policy.linkerd.io \ No newline at end of file diff --git a/cmd/policygen/templates/linkerd/application/meshtlsauthentication.yaml b/cmd/policygen/templates/linkerd/application/meshtlsauthentication.yaml index f956c9e..b16b44c 100644 --- a/cmd/policygen/templates/linkerd/application/meshtlsauthentication.yaml +++ b/cmd/policygen/templates/linkerd/application/meshtlsauthentication.yaml @@ -2,13 +2,16 @@ apiVersion: policy.linkerd.io/v1alpha1 kind: MeshTLSAuthentication metadata: - name: {{ .app.Name }}-p{{.port}} - namespace: {{ .app.Namespace.Name }} + name: {{ .Name }} + namespace: {{ .Namespace.Name }} spec: + {{- if .ServiceAccounts }} identityRefs: - {{- range $sa := .serviceAccounts }} + {{- range $sa := .ServiceAccounts }} - kind: ServiceAccount - name: {{ $sa.Name }} - namespace: {{ $sa.Namespace }} + name: {{ $sa }} {{- end }} + {{- else }} + fail (printf "no service accounts defined for app %s" .Name ) + {{- end}}