eliminating duplicate communications. this caused problems with linkerd

and helm
This commit is contained in:
Erik Brakkee 2025-01-25 14:49:33 +01:00
parent cd4023f5ce
commit 2bea96cc57
5 changed files with 84 additions and 94 deletions

View File

@ -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)
}
}
}

View File

@ -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)

View File

@ -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

View File

@ -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 }}

View File

@ -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}}