From 1228c4a3166300c6b03d45ce96c0704f937f40ce Mon Sep 17 00:00:00 2001 From: Aleksandr Tarasov Date: Mon, 5 Sep 2022 17:22:54 +0400 Subject: [PATCH] support new resource (#4) --- .gitignore | 3 +- README.md | 10 +- charts/linkerd-easyauth/Chart.yaml | 4 +- .../templates/auth-policies.yml | 99 +++++++++++-------- .../templates/easyauth-injector.yml | 2 +- charts/linkerd-easyauth/values.yaml | 5 +- cmd/authcheck.go | 41 +++++++- cmd/k8s.go | 31 ++++-- 8 files changed, 128 insertions(+), 67 deletions(-) diff --git a/.gitignore b/.gitignore index 0ca2a00..b4bb630 100644 --- a/.gitignore +++ b/.gitignore @@ -12,5 +12,4 @@ # Output of the go coverage tool, specifically when used with LiteIDE *.out -# Dependency directories (remove the comment below to include it) -# vendor/ +.values.yml \ No newline at end of file diff --git a/README.md b/README.md index 3464c94..eb8eb89 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,9 @@ Simplify the Linkerd Authorization Policies management according to [the article | 2.11.x | 0.1.0 - 0.4.0 | | 2.12.x | \>= 0.5.0 | -New `AuthorizationPolicy` and `HTTPRoute` are in WIP. Their support will be soon. +New `AuthorizationPolicy` are supported since `0.6.0`. + +New `HTTPRoute` are in WIP. Its support will be soon. ## How to use it @@ -22,7 +24,7 @@ linkerd easyauth [COMMAND] -n [FLAGS] ``` ### Supported commands -- `authcheck`: checks for obsolete `Server` and `ServerAuthorization` resources, checks that PODs ports have `Server` resource +- `authcheck`: checks for obsolete `Server` and policies resources like `ServerAuthorization` and `AuthorizationPolicy`, checks that PODs ports have `Server` resource - `list`: list of Pods that were injected by `linkerd.io/easyauth-enabled: true` annotation (more information below) - `authz`: fast implementation for fetch the list server authorizations for a resource (use caching) @@ -40,7 +42,7 @@ Install the helm chart with injector and policies: ### What the helm chart provides - Injector that adds `linkerd.io/easyauth-enabled: true` label for all meshed pods (you can limit namespaces via helmchart) - `Server` in terms of Linkerd authorization policies for `linkerd-admin-port` -- `ServerAuthorization` resources that provides basic allow policies for ingress, Linkerd itself, and monitoring +- `AuthorizationPolicy` resources that provides basic allow policies for ingress, Linkerd itself, and monitoring ### What the helm chart does not provide Because the `Server` should be one per service per port, we can define the server for the linkerd proxy admin port only. @@ -63,7 +65,7 @@ spec: ### Important Values #### Meshed Apps Namespaces -Because all `ServerAuthorization` policies are Namespaced scope then we should add common policies to each namespace with our apps: +Because all `AuthorizationPolicy` policies are Namespaced scope then we should add common policies to each namespace with our apps: ``` meshedApps: namespaces: diff --git a/charts/linkerd-easyauth/Chart.yaml b/charts/linkerd-easyauth/Chart.yaml index 3eda358..3d5f1de 100644 --- a/charts/linkerd-easyauth/Chart.yaml +++ b/charts/linkerd-easyauth/Chart.yaml @@ -1,5 +1,5 @@ apiVersion: v1 -appVersion: "0.5.0" +appVersion: "0.6.0" description: A Helm chart for Linkerd easyauth extension. name: linkerd-easyauth -version: "0.5.0" \ No newline at end of file +version: "0.6.0" \ No newline at end of file diff --git a/charts/linkerd-easyauth/templates/auth-policies.yml b/charts/linkerd-easyauth/templates/auth-policies.yml index 703db52..234b3e9 100644 --- a/charts/linkerd-easyauth/templates/auth-policies.yml +++ b/charts/linkerd-easyauth/templates/auth-policies.yml @@ -5,72 +5,87 @@ kind: Server metadata: namespace: {{ . }} name: linkerd-admin-port - labels: - linkerd.io/server-type: common spec: podSelector: matchLabels: - linkerd.io/easyauth: true + linkerd.io/easyauth: "true" port: linkerd-admin --- -apiVersion: policy.linkerd.io/v1beta1 -kind: Server +apiVersion: policy.linkerd.io/v1alpha1 +kind: MeshTLSAuthentication metadata: namespace: {{ . }} - name: app-serving-port - labels: - linkerd.io/server-type: common + name: linkerd-authn spec: - podSelector: - matchLabels: - linkerd.io/easyauth: true - port: linkerd-admin + identities: + {{- range $.Values.policies.linkerd.namespaces }} + - "*.{{ . }}.serviceaccount.identity.linkerd.cluster.local" + {{- end }} --- -apiVersion: policy.linkerd.io/v1beta1 -kind: ServerAuthorization +apiVersion: policy.linkerd.io/v1alpha1 +kind: AuthorizationPolicy metadata: namespace: {{ . }} name: linkerd-admin-allow spec: - server: + targetRef: + group: policy.linkerd.io + kind: Server name: linkerd-admin-port - client: - meshTLS: - identities: - {{- range $.Values.policies.linkerd.namespaces }} - - "*.{{ . }}.serviceaccount.identity.linkerd.cluster.local" - {{- end }} ---- + requiredAuthenticationRefs: + - name: linkerd-authn + kind: MeshTLSAuthentication + group: policy.linkerd.io {{- if $.Values.policies.monitoring.enabled }} -apiVersion: policy.linkerd.io/v1beta1 -kind: ServerAuthorization +--- +apiVersion: policy.linkerd.io/v1alpha1 +kind: MeshTLSAuthentication +metadata: + namespace: {{ . }} + name: monitoring-authn +spec: + identities: + - "*.{{ $.Values.policies.monitoring.namespace }}.serviceaccount.identity.linkerd.cluster.local" +--- +apiVersion: policy.linkerd.io/v1alpha1 +kind: AuthorizationPolicy metadata: namespace: {{ . }} name: linkerd-monitoring-allow spec: - server: - selector: - matchLabels: - linkerd.io/server-type: common - client: - meshTLS: - identities: - - "*.{{ $.Values.policies.monitoring.namespace }}.serviceaccount.identity.linkerd.cluster.local" + targetRef: + group: core + kind: Namespace + name: {{ . }} + requiredAuthenticationRefs: + - name: monitoring-authn + kind: MeshTLSAuthentication + group: policy.linkerd.io {{ end }} {{- if $.Values.policies.ingress.enabled }} -apiVersion: policy.linkerd.io/v1beta1 -kind: ServerAuthorization +--- +apiVersion: policy.linkerd.io/v1alpha1 +kind: MeshTLSAuthentication +metadata: + namespace: {{ . }} + name: ingress-authn +spec: + identities: + - "*.{{ $.Values.policies.ingress.namespace }}.serviceaccount.identity.linkerd.cluster.local" +--- +apiVersion: policy.linkerd.io/v1alpha1 +kind: AuthorizationPolicy metadata: namespace: {{ . }} name: linkerd-ingress-allow spec: - server: - selector: - matchLabels: - linkerd.io/server-type: common - client: - meshTLS: - identities: - - "*.{{ $.Values.policies.ingress.namespace }}.serviceaccount.identity.linkerd.cluster.local" + targetRef: + group: core + kind: Namespace + name: {{ . }} + requiredAuthenticationRefs: + - name: ingress-authn + kind: MeshTLSAuthentication + group: policy.linkerd.io {{ end }} {{ end }} \ No newline at end of file diff --git a/charts/linkerd-easyauth/templates/easyauth-injector.yml b/charts/linkerd-easyauth/templates/easyauth-injector.yml index 94fb9ff..0d8a0e2 100644 --- a/charts/linkerd-easyauth/templates/easyauth-injector.yml +++ b/charts/linkerd-easyauth/templates/easyauth-injector.yml @@ -11,7 +11,7 @@ metadata: name: easyauth-injector namespace: {{.Values.namespace}} spec: - replicas: 1 + replicas: {{ .Values.webhook.replicas }} selector: matchLabels: linkerd.io/extension: easyauth diff --git a/charts/linkerd-easyauth/values.yaml b/charts/linkerd-easyauth/values.yaml index ea075a4..6b29839 100644 --- a/charts/linkerd-easyauth/values.yaml +++ b/charts/linkerd-easyauth/values.yaml @@ -9,9 +9,12 @@ tolerations: &default_tolerations webhook: image: name: aatarasoff/linkerd-easyauth-webhook - version: 0.1.0 + version: 0.6.0 pullPolicy: IfNotPresent + # modify to HA mode + replicas: 1 + logLevel: info failurePolicy: Fail diff --git a/cmd/authcheck.go b/cmd/authcheck.go index 7333dbd..9fc0a8b 100644 --- a/cmd/authcheck.go +++ b/cmd/authcheck.go @@ -83,13 +83,14 @@ func easyAuthCategory(resources *K8sResources) *healthcheck.Category { checkers := []healthcheck.Checker{} checkers = append(checkers, - *healthcheck.NewChecker("linkerd-easyauth no Server without ServerAuthorizations"). + *healthcheck.NewChecker("linkerd-easyauth no Server without authorization policies"). Warning(). WithCheck(func(ctx context.Context) error { serversWOServerAuthorizations := []string{} for _, server := range resources.Servers { founded := false + for _, serverAuthorization := range resources.ServerAuthorizations { selector, err := metav1.LabelSelectorAsSelector(serverAuthorization.Spec.Server.Selector) if err != nil { @@ -105,19 +106,30 @@ func easyAuthCategory(resources *K8sResources) *healthcheck.Category { } } + for _, policy := range resources.AuthorizationPolicies { + // namespaced policies applies on each server + if policy.Spec.TargetRef.Kind == "Namespace" { + founded = true + } + + if string(policy.Spec.TargetRef.Name) == server.GetName() { + founded = true + } + } + if !founded { - serversWOServerAuthorizations = append(serversWOServerAuthorizations, fmt.Sprintf("Server %s has no ServerAuthorizarions", server.GetName())) + serversWOServerAuthorizations = append(serversWOServerAuthorizations, fmt.Sprintf("Server %s has no authorization policies", server.GetName())) } } if len(serversWOServerAuthorizations) == 0 { return nil } - return fmt.Errorf("Some servers have no ServerAuthorizations:\n\t%s", strings.Join(serversWOServerAuthorizations, "\n\t")) + return fmt.Errorf("Some servers have no authorization policies:\n\t%s", strings.Join(serversWOServerAuthorizations, "\n\t")) })) checkers = append(checkers, - *healthcheck.NewChecker("linkerd-easyauth no ServerAuthorizations without Server"). + *healthcheck.NewChecker("linkerd-easyauth no authorization policies without Server"). Warning(). WithCheck(func(ctx context.Context) error { serverAuthorizationsWOServer := []string{} @@ -140,7 +152,26 @@ func easyAuthCategory(resources *K8sResources) *healthcheck.Category { } if !founded { - serverAuthorizationsWOServer = append(serverAuthorizationsWOServer, fmt.Sprintf("ServerAuthorizarions %s do not apply to any Server", serverAuthorization.GetName())) + serverAuthorizationsWOServer = append(serverAuthorizationsWOServer, fmt.Sprintf("ServerAuthorizarions %s does not apply to any Server", serverAuthorization.GetName())) + } + } + + for _, policy := range resources.AuthorizationPolicies { + founded := false + + if policy.Spec.TargetRef.Kind == "Namespace" { + // at least one Server should exist + founded = len(resources.Servers) > 0 + } else { + for _, server := range resources.Servers { + if policy.Spec.TargetRef.Kind == "Server" && (string(policy.Spec.TargetRef.Name) == server.GetName()) { + founded = true + } + } + } + + if !founded { + serverAuthorizationsWOServer = append(serverAuthorizationsWOServer, fmt.Sprintf("Authorization Policy %s does not apply to any Server", policy.GetName())) } } diff --git a/cmd/k8s.go b/cmd/k8s.go index 379bd5e..0aa3d8f 100644 --- a/cmd/k8s.go +++ b/cmd/k8s.go @@ -3,8 +3,9 @@ package cmd import ( "context" "fmt" - "github.com/linkerd/linkerd2/controller/gen/apis/server/v1beta1" - beta1 "github.com/linkerd/linkerd2/controller/gen/apis/serverauthorization/v1beta1" + policy "github.com/linkerd/linkerd2/controller/gen/apis/policy/v1alpha1" + server "github.com/linkerd/linkerd2/controller/gen/apis/server/v1beta1" + saz "github.com/linkerd/linkerd2/controller/gen/apis/serverauthorization/v1beta1" l5dcrdinformer "github.com/linkerd/linkerd2/controller/gen/client/informers/externalversions" pkgK8s "github.com/linkerd/linkerd2/controller/k8s" "github.com/linkerd/linkerd2/pkg/k8s" @@ -17,10 +18,11 @@ import ( ) type K8sResources struct { - Pods *v1.PodList - Services *v1.ServiceList - Servers []*v1beta1.Server - ServerAuthorizations []*beta1.ServerAuthorization + Pods *v1.PodList + Services *v1.ServiceList + Servers []*server.Server + ServerAuthorizations []*saz.ServerAuthorization + AuthorizationPolicies []*policy.AuthorizationPolicy } func FetchK8sResources(ctx context.Context, namespace string) (*K8sResources, error) { @@ -51,11 +53,17 @@ func FetchK8sResources(ctx context.Context, namespace string) (*K8sResources, er return nil, err } + authorizationPolicies, err := lr5dAPI.Policy().V1alpha1().AuthorizationPolicies().Lister().AuthorizationPolicies(namespace).List(labels.NewSelector()) + if err != nil { + return nil, err + } + return &K8sResources{ - Pods: pods, - Services: services, - Servers: servers, - ServerAuthorizations: serverAuthorizations, + Pods: pods, + Services: services, + Servers: servers, + ServerAuthorizations: serverAuthorizations, + AuthorizationPolicies: authorizationPolicies, }, nil } @@ -77,6 +85,9 @@ func initServerAPI(kubeconfigPath string) l5dcrdinformer.SharedInformerFactory { stopCh := make(chan struct{}) go lr5dAPI.Server().V1beta1().Servers().Informer().Run(stopCh) go lr5dAPI.Serverauthorization().V1beta1().ServerAuthorizations().Informer().Run(stopCh) + go lr5dAPI.Policy().V1alpha1().AuthorizationPolicies().Informer().Run(stopCh) + go lr5dAPI.Policy().V1alpha1().MeshTLSAuthentications().Informer().Run(stopCh) + go lr5dAPI.Policy().V1alpha1().NetworkAuthentications().Informer().Run(stopCh) ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel()