apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: inject-auth-sidecar annotations: pod-policies.kyverno.io/autogen-controllers: none policies.kyverno.io/title: Inject Auth Sidecar policies.kyverno.io/minversion: 1.6.0 policies.kyverno.io/category: Security policies.kyverno.io/severity: medium policies.kyverno.io/subject: Pod policies.kyverno.io/description: >- Injects an auth sidecar container into Pods annotated with policies.forteapps.io/auth: "true". The sidecar proxies requests through a token-based auth layer and a NetworkPolicy is generated to restrict ingress to the sidecar port only. If the auth-tokens Secret does not exist in the namespace, an empty one is created to prevent volume mount failures. Upstream URL and image can be overridden via policies.forteapps.io/auth-upstream-url and policies.forteapps.io/auth-image annotations. When auth-upstream-url is not set, the first containerPort of the first existing container is used. spec: background: false rules: - name: inject-sidecar skipBackgroundRequests: true match: any: - resources: kinds: - Pod annotations: policies.forteapps.io/auth: "true" exclude: any: - resources: namespaces: - kube-system - kyverno - argocd - cert-manager - monitoring context: - name: appPort variable: jmesPath: request.object.spec.containers[?name != 'authn'] | [0].ports[0].containerPort || `3000` mutate: patchStrategicMerge: spec: containers: - name: authn image: "{{ request.object.metadata.annotations.\"policies.forteapps.io/auth-image\" || 'ghcr.io/snothub/stunning-memory' }}:{{ request.object.metadata.annotations.\"policies.forteapps.io/auth-image-version\" || 'latest' }}" ports: - containerPort: 8080 name: auth protocol: TCP env: - name: AUTH_LISTEN_ADDR value: ":8080" - name: AUTH_UPSTREAM_URL value: "{{ request.object.metadata.annotations.\"policies.forteapps.io/auth-upstream-url\" || join('', ['http://localhost:', to_string(appPort)]) }}" - name: AUTH_TOKEN_FILE value: "/etc/auth/tokens" - name: AUTH_MODE value: "token" volumeMounts: - name: auth-tokens mountPath: /etc/auth readOnly: true resources: limits: cpu: 50m memory: 64Mi requests: cpu: 10m memory: 32Mi readinessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 2 periodSeconds: 5 livenessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 5 periodSeconds: 10 securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: - ALL volumes: - name: auth-tokens secret: secretName: auth-tokens optional: true - name: generate-auth-tokens-secret skipBackgroundRequests: true match: any: - resources: kinds: - Pod annotations: policies.forteapps.io/auth: "true" exclude: any: - resources: namespaces: - kube-system - kyverno - argocd - cert-manager - monitoring preconditions: all: - key: "{{ request.operation }}" operator: In value: - CREATE generate: synchronize: false apiVersion: v1 kind: Secret name: auth-tokens namespace: "{{ request.namespace }}" data: metadata: labels: app.kubernetes.io/managed-by: kyverno app.kubernetes.io/created-by: inject-auth-sidecar type: Opaque data: {} - name: generate-auth-network-policy skipBackgroundRequests: true match: any: - resources: kinds: - Pod annotations: policies.forteapps.io/auth: "true" exclude: any: - resources: namespaces: - kube-system - kyverno - argocd - cert-manager - monitoring preconditions: all: - key: "{{ request.operation }}" operator: In value: - CREATE generate: synchronize: false apiVersion: networking.k8s.io/v1 kind: NetworkPolicy name: "{{ request.object.metadata.name }}-auth-ingress" namespace: "{{ request.namespace }}" data: metadata: labels: app.kubernetes.io/managed-by: kyverno app.kubernetes.io/created-by: inject-auth-sidecar spec: podSelector: matchLabels: "{{ request.object.metadata.labels }}" policyTypes: - Ingress ingress: - ports: - port: 8080 protocol: TCP