package main import ( "fmt" "io" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "os" "slices" "strings" ) type LinkerdPolicyGenerator struct { config *Config policyTemplates *PolicyTemplates apps map[string]*Application networks map[string]*Network } func NewLinkerdPolicyGenerator(config *Config, templates *PolicyTemplates) *LinkerdPolicyGenerator { return &LinkerdPolicyGenerator{ config: config, policyTemplates: templates, apps: make(map[string]*Application), networks: make(map[string]*Network), } } func (g *LinkerdPolicyGenerator) Init(writer io.Writer) error { return nil } func (g *LinkerdPolicyGenerator) GenerateNamespace(writer io.Writer, namespace *Namespace) error { return nil } func (g *LinkerdPolicyGenerator) GenerateCommunicationRule( writer io.Writer, app *Application, ingress *Ingress, egress *Egress) error { if app.Namespace.Unauthorized { fmt.Fprintf(os.Stderr, "UNAUTHORIZED %s\n", app.Name) return nil } // and the server resources fmt.Fprintf(os.Stderr, "Server %s/%s\n", app.Namespace.Name, app.Name) err := g.policyTemplates.Execute("linkerd", "server", writer, app) if err != nil { return err } for _, ingress := range ingress.Applications { for _, port := range ingress.Ports { if port.Protocol != "TCP" { continue } g.apps[ingress.Application.Name] = ingress.Application err = g.policyTemplates.Execute("linkerd", "authorizationpolicy-app", writer, map[string]any{ "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 } } } return nil } func (g *LinkerdPolicyGenerator) serviceAccounts(peers []*ApplicationPeer) []v1.ServiceAccount { serviceAccounts := []v1.ServiceAccount{} for _, peer := range peers { for _, sa := range peer.Application.ServiceAccounts { serviceAccounts = append(serviceAccounts, v1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Name: sa, Namespace: peer.Application.Namespace.Name, }, }) } } slices.SortFunc(serviceAccounts, func(s1 v1.ServiceAccount, s2 v1.ServiceAccount) int { return strings.Compare(s1.Namespace+"/"+s1.Name, s2.Namespace+"/"+s2.Name) }) return slices.CompactFunc(serviceAccounts, func(s1, s2 v1.ServiceAccount) bool { return s1.Namespace == s2.Namespace && s1.Name == s2.Name }) } 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) if err != nil { return err } } return nil }