158 lines
4.4 KiB
Go
158 lines
4.4 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"slices"
|
|
"strconv"
|
|
)
|
|
|
|
type LinkerdPolicyGenerator struct {
|
|
config *Config
|
|
policyTemplates *PolicyTemplates
|
|
|
|
networks map[string]*Network
|
|
}
|
|
|
|
func NewLinkerdPolicyGenerator(config *Config, templates *PolicyTemplates) *LinkerdPolicyGenerator {
|
|
return &LinkerdPolicyGenerator{
|
|
config: config,
|
|
policyTemplates: templates,
|
|
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
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|