From 4c6aa91ca629cb147684be2b7d1032d0b5922f68 Mon Sep 17 00:00:00 2001 From: Ronen Hilewicz Date: Thu, 26 Sep 2024 17:08:40 -0400 Subject: [PATCH 01/19] WIP: initial topaz chart --- charts/topaz/.helmignore | 23 ++ charts/topaz/Chart.lock | 6 + charts/topaz/Chart.yaml | 29 ++ charts/topaz/templates/NOTES.txt | 22 ++ charts/topaz/templates/_helpers.tpl | 186 +++++++++++ charts/topaz/templates/config.yaml | 154 +++++++++ charts/topaz/templates/deployment.yaml | 68 ++++ charts/topaz/templates/hpa.yaml | 32 ++ charts/topaz/templates/ingress.yaml | 61 ++++ charts/topaz/templates/service.yaml | 15 + charts/topaz/templates/serviceaccount.yaml | 13 + .../templates/tests/test-connection.yaml | 15 + charts/topaz/values.yaml | 312 ++++++++++++++++++ 13 files changed, 936 insertions(+) create mode 100644 charts/topaz/.helmignore create mode 100644 charts/topaz/Chart.lock create mode 100644 charts/topaz/Chart.yaml create mode 100644 charts/topaz/templates/NOTES.txt create mode 100644 charts/topaz/templates/_helpers.tpl create mode 100644 charts/topaz/templates/config.yaml create mode 100644 charts/topaz/templates/deployment.yaml create mode 100644 charts/topaz/templates/hpa.yaml create mode 100644 charts/topaz/templates/ingress.yaml create mode 100644 charts/topaz/templates/service.yaml create mode 100644 charts/topaz/templates/serviceaccount.yaml create mode 100644 charts/topaz/templates/tests/test-connection.yaml create mode 100644 charts/topaz/values.yaml diff --git a/charts/topaz/.helmignore b/charts/topaz/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/charts/topaz/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/topaz/Chart.lock b/charts/topaz/Chart.lock new file mode 100644 index 0000000..91c20a8 --- /dev/null +++ b/charts/topaz/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: aserto-lib + repository: oci://ghcr.io/aserto-dev/helm + version: 0.1.3 +digest: sha256:ce25ed7c67b00cdfb3d17ddb8bc80146ba94f6a6ebdb1c7a7004ee67fcee4bac +generated: "2024-09-23T14:11:57.386406-04:00" diff --git a/charts/topaz/Chart.yaml b/charts/topaz/Chart.yaml new file mode 100644 index 0000000..13c8517 --- /dev/null +++ b/charts/topaz/Chart.yaml @@ -0,0 +1,29 @@ +apiVersion: v2 +name: topaz +description: Helm chart for the Topaz authorizer + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "0.32.26" + +dependencies: + - name: aserto-lib + version: ~0.1.3 + repository: oci://ghcr.io/aserto-dev/helm diff --git a/charts/topaz/templates/NOTES.txt b/charts/topaz/templates/NOTES.txt new file mode 100644 index 0000000..01cf764 --- /dev/null +++ b/charts/topaz/templates/NOTES.txt @@ -0,0 +1,22 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "topaz.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch its status by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "topaz.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "topaz.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "topaz.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/charts/topaz/templates/_helpers.tpl b/charts/topaz/templates/_helpers.tpl new file mode 100644 index 0000000..611a0e8 --- /dev/null +++ b/charts/topaz/templates/_helpers.tpl @@ -0,0 +1,186 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "topaz.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "topaz.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "topaz.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "topaz.labels" -}} +helm.sh/chart: {{ include "topaz.chart" . }} +{{ include "topaz.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "topaz.selectorLabels" -}} +app.kubernetes.io/name: {{ include "topaz.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "topaz.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "topaz.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Remote directory configuration +*/}} +{{- define "topaz.remoteDirectory" -}} +address: {{ ((.Values.directory).remote).address }} +{{- if not (empty ((.Values.directory).remote).tenantID) }} +tenant_id: {{ ((.Values.directory).remote).tenantID }} +{{- end }} +{{- if not (empty ((.Values.directory).remote).apiKey) }} +api_key: {{ ((.Values.directory).remote).apiKey }} +{{- end }} +{{- if ((.Values.directory).remote).skipTLSVerification }} +insecure: true +{{- end }} +{{- if not (empty ((.Values.directory).remote).caCert | and (empty ((.Values.directory).remote).caCertSecret)) }} +ca_cert_path: /directory-certs/ca.crt +{{- end }} +{{- if not (empty ((.Values.directory).remote).additionalHeaders) }} +headers: + {{ toYaml ((.Values.directory).remote).additionalHeaders | toYaml | nindent 2 }} +{{- end }} +{{- end }} + +{{/* +Topaz API key configuration +*/}} +{{- define "topaz.apiKeys" -}} +{{- range .Values.auth.apiKeys }} +{{- if .key -}} +"{{ .key }}": root-key +{{- else if .secretName -}} +{{- $secretKey := .secretKey | default "api-key" }} +{{- $varName := printf "${API_KEY_%s_%s}" .secretName $secretKey | upper | replace "-" "_" }} +"{{ $varName }}": root-key +{{- end}} +{{- end }} +{{- end }} + +{{- define "topaz.discoveryKey" -}} +{{- if .apiKey -}} +{{- .apiKey }} +{{- else if .apiKeySecret | and .apiKeySecret.name -}} +"${DISCOVERY_API_KEY}" +{{- else }} +{{ fail "either apiKey or apiKeySecret must be set in opa.policy.discovery" }} +{{- end }} +{{- end }} + +{{- define "topaz.ociCredentials" -}} +{{- if .apiKeySecret -}} +"${REGISTRY_API_KEY}" +{{- else if .user }} +{{ printf "%s:%s" .user .apiKey }} +{{- else }} +{{ .apiKey }} +{{- end }} +{{- end }} + +{{- define "topaz.svcDependencies" -}} +{{- $deps := dict "reader" "model" "writer" "model" "importer" "model" "authorizer" "reader" "console" "authorizer" }} +{{- $dep := get $deps .service }} +{{- if $dep -}} +needs: + - {{ $dep }} +{{- end }} +{{- end }} + +{{- define "topaz.grpcService" -}} +{{- $values := first . -}} +{{- $svc := last . -}} +{{- $global := $values.http -}} +{{- $cfg := merge (dig $svc "grpc" dict $values.serviceOverrides) $values.grpc -}} +listen_address: 0.0.0.0:{{ $cfg.port | default "8282" }} +connection_timeout_seconds: {{ $cfg.connectionTimeoutSec | default "2" }} +{{- end }} + + +{{- define "topaz.gatewayService" -}} +{{- $values := first . -}} +{{- $svc := last . -}} +{{- $cfg := merge (dig $svc "http" dict $values.serviceOverrides) $values.http -}} +listen_address: 0.0.0.0:{{ $cfg.port | default "8383" }} + +{{- if $cfg.domain }} +fdqn: {{ $cfg.domain }} +{{- end }} + +{{- if $cfg.allowedHeaders }} +allowed_headers: +{{- $cfg.allowedHeaders | default list | toYaml | nindent 2 }} +{{- end }} + +{{- if $cfg.allowedMethods }} +allowed_methods: +{{- $cfg.allowedMethods | default list | toYaml | nindent 2 }} +{{- end }} + +{{- if $cfg.allowedOrigins }} +allowed_origins: +{{- $cfg.allowedOrigins | default list | toYaml | nindent 2 }} +{{- end }} + +{{- if $cfg.noTLS }} +http: false +{{- end }} +read_timeout: {{ $cfg.readTimeout | default "2s" }} +read_header_timeout: {{ $cfg.readHeaderTimeout | default "2s" }} +write_timeout: {{ $cfg.writeTimeout | default "2s" }} +idle_timeout: {{ $cfg.idleTimeout | default "30s" }} +{{- end }} + +{{- define "topaz.discoveryResource" -}} +{{- printf "%s/%s/opa" .policyName .policyName }} +{{- end }} + +{{- define "topaz.enabledServices" -}} +{{- $services := list "authorizer" "model" "reader" | + concat (((.Values.directory).edge).services | default list) }} +{{- if .Values.console.enabled }} +{{- $services = append $services "console" }} +{{- end }} +{{- $services | toJson }} +{{- end }} diff --git a/charts/topaz/templates/config.yaml b/charts/topaz/templates/config.yaml new file mode 100644 index 0000000..5813e10 --- /dev/null +++ b/charts/topaz/templates/config.yaml @@ -0,0 +1,154 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "topaz.fullname" . }}-config + labels: + {{- include "topaz.labels" . | nindent 4 }} +stringData: + config.yaml: | + # yaml-language-server: $schema=https://topaz.sh/schema/config.json + --- + version: 2 + + logging: + prod: true + log_level: {{ .Values.logLevel | default "info" }} + grpc_log_level: {{ .Values.grpcLogLevel | default "info" }} + + {{ if empty ((.Values.directory).remote).address -}} + directory: + db_path: '${TOPAZ_DB_DIR}/directory.db' + request_timeout: {{ ((.Values.directory).edge).openTimeout | default "5s" }} + + # TODO: apply 'reader' configuration + remote_directory: + address: 0.0.0.0:9292 + api_key: "TODO: use reader key if configured" + ca_cert_path: "TODO: point to topaz CA cert" + timeout_in_seconds: {{ ((.Values.directory).remote).timeoutSeconds | default "5" }} + {{- else -}} + remote_directory: + {{- include "topaz.remoteDirectory" . | nindent 6 }} + {{- end }} + + jwt: + acceptable_time_skew_seconds: {{ .Values.jwtAcceptableSkewSeconds | default "5"}} + + # authentication configuration + auth: + {{- if not (empty (.Values.auth).apiKeys) }} + api_keys: + {{- include "topaz.apiKeys" . | nindent 8 }} + {{- end }} + options: + default: + enable_api_key: {{ print (not (empty (.Values.auth).apiKeys)) }} + enable_anonymous: {{ print (empty (.Values.auth).apiKeys) }} + overrides: + paths: + - /aserto.authorizer.v2.Authorizer/Info + - /grpc.reflection.v1.ServerReflection/ServerReflectionInfo + - /grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo + override: + enable_api_key: false + enable_anonymous: true + + api: + health: + listen_address: 0.0.0.0:{{ include "aserto-lib.healthPort" . }} + certs: + tls_key_path: '${TOPAZ_CERTS_DIR}/gateway.key' + tls_cert_path: '${TOPAZ_CERTS_DIR}/gateway.crt' + tls_ca_cert_path: '${TOPAZ_CERTS_DIR}/gateway-ca.crt' + + {{- if (.Values.metrics).enabled }} + metrics: + {{- include "aserto-lib.metricsService" . | nindent 8 }} + certs: + tls_key_path: '${TOPAZ_CERTS_DIR}/gateway.key' + tls_cert_path: '${TOPAZ_CERTS_DIR}/gateway.crt' + tls_ca_cert_path: '${TOPAZ_CERTS_DIR}/gateway-ca.crt' + {{- end }} + + services: + {{- range (include "topaz.enabledServices" . | fromJsonArray) }} + {{ . }}: + {{- include "topaz.svcDependencies" (dict "service" .) | nindent 10 }} + {{- if not (eq . "console") }} + grpc: + {{- include "topaz.grpcService" (list $.Values .) | nindent 12 }} + certs: + tls_key_path: '${TOPAZ_CERTS_DIR}/grpc.key' + tls_cert_path: '${TOPAZ_CERTS_DIR}/grpc.crt' + tls_ca_cert_path: '${TOPAZ_CERTS_DIR}/grpc-ca.crt' + {{- end }} + gateway: + {{- include "topaz.gatewayService" (list $.Values .) | nindent 12 }} + certs: + tls_key_path: '${TOPAZ_CERTS_DIR}/gateway.key' + tls_cert_path: '${TOPAZ_CERTS_DIR}/gateway.crt' + tls_ca_cert_path: '${TOPAZ_CERTS_DIR}/gateway-ca.crt' + {{- end }} + + opa: + instance_id: {{ .Values.tenantID | default (quote "-") }} + graceful_shutdown_period_seconds: {{ (.Values.opa).gracefuShutdownPeriodSeconds | default "2" }} + max_plugin_wait_time_seconds: {{ (.Values.opa).maxPluginWaitTimeSeconds | default "30" }} + local_bundles: + paths: [] + skip_verification: true + config: + persistence_directory: "/opa-persistence" + services: + {{- if ((.Values.opa).policy).discovery | and ((.Values.opa).policy).oci }} + {{- fail "opa.policy.discovery and opa.policy.oci are mutually exclusive" }} + {{- end }} + + {{- if ((.Values.opa).policy).oci }} + {{- with ((.Values.opa).policy).oci }} + oci: + type: oci + url: {{ .registry | required "opa.policy.oci.registry is required" }} + {{- if (.apiKey | or .apiKeySecret) }} + credentials: + bearer: + scheme: basic + token: {{ include "topaz.ociCredentials" . }} + {{- else }} + {{- fail "either opa.policy.discovery or opa.policy.oci must be set"}} + {{- end }} + {{- .serviceConfig | default dict | toYaml | nindent 12 }} + bundles: + topaz_policy: + service: oci + resource: {{ .image | required "opa.policy.oci.image is required" }} + persist: {{ $.Values.opa.persistence.enabled | default "false" }} + {{- if .bundleConfig }} + config: + {{- .bundleConfig | toYaml | nindent 14 }} + {{- end }} + {{- end }} + {{- else if ((.Values.opa).policy).discovery }} + {{- with ((.Values.opa).policy).discovery }} + discovery: + url: {{ .url | default "https://discovery.prod.aserto.com/api/v2/discovery" }} + credentials: + bearer: + token: {{ include "topaz.discoveryKey" .}} + scheme: "basic" + {{- $cfg := .serviceConfig | default dict -}} + {{- $headers := dig "headers" dict $cfg -}} + {{ $cfg = unset $cfg "headers" }} + headers: + Aserto-Tenant-Id: {{ $.Values.tenantID | required "policy discovery requires tenantID to be set" }} + {{- if $headers }} + {{- $headers | toYaml | nindent 14 }} + {{- end }} + {{- $cfg | default dict | toYaml | nindent 12 }} + discovery: + service: discovery + resource: {{ include "topaz.discoveryResource" . }} + persist: {{ $.Values.opa.persistence.enabled | default "false" }} + {{- end }} + {{- end }} diff --git a/charts/topaz/templates/deployment.yaml b/charts/topaz/templates/deployment.yaml new file mode 100644 index 0000000..5871204 --- /dev/null +++ b/charts/topaz/templates/deployment.yaml @@ -0,0 +1,68 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "topaz.fullname" . }} + labels: + {{- include "topaz.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "topaz.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "topaz.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "topaz.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: {{ .Values.service.port }} + protocol: TCP + livenessProbe: + {{- toYaml .Values.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.readinessProbe | nindent 12 }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.volumeMounts }} + volumeMounts: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.volumes }} + volumes: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/topaz/templates/hpa.yaml b/charts/topaz/templates/hpa.yaml new file mode 100644 index 0000000..0be37fd --- /dev/null +++ b/charts/topaz/templates/hpa.yaml @@ -0,0 +1,32 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "topaz.fullname" . }} + labels: + {{- include "topaz.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "topaz.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/charts/topaz/templates/ingress.yaml b/charts/topaz/templates/ingress.yaml new file mode 100644 index 0000000..64070bd --- /dev/null +++ b/charts/topaz/templates/ingress.yaml @@ -0,0 +1,61 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "topaz.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "topaz.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/topaz/templates/service.yaml b/charts/topaz/templates/service.yaml new file mode 100644 index 0000000..dd8a176 --- /dev/null +++ b/charts/topaz/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "topaz.fullname" . }} + labels: + {{- include "topaz.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "topaz.selectorLabels" . | nindent 4 }} diff --git a/charts/topaz/templates/serviceaccount.yaml b/charts/topaz/templates/serviceaccount.yaml new file mode 100644 index 0000000..7683c21 --- /dev/null +++ b/charts/topaz/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "topaz.serviceAccountName" . }} + labels: + {{- include "topaz.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automount }} +{{- end }} diff --git a/charts/topaz/templates/tests/test-connection.yaml b/charts/topaz/templates/tests/test-connection.yaml new file mode 100644 index 0000000..184cf74 --- /dev/null +++ b/charts/topaz/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "topaz.fullname" . }}-test-connection" + labels: + {{- include "topaz.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "topaz.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/charts/topaz/values.yaml b/charts/topaz/values.yaml new file mode 100644 index 0000000..bca9651 --- /dev/null +++ b/charts/topaz/values.yaml @@ -0,0 +1,312 @@ +# Default values for topaz. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +image: + repository: ghcr.io/aserto-dev/topaz + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + # tag: x.y.z + +# Set the service log level (trace/debug/info/warn/error) +logLevel: info + +# Set gRPC log level (trace/debug/info/warn/error) +grpcLogLevel: info + +# Directory configuration. +# Using a local directory by default. +directory: + # Local edge directory configuration. + edge: + # Timeout for loading the local database. + openTimeout: 5s + # Persistent volume for the local directory. + persistence: + enabled: false + # PersistentVolumeClaim options. + # See https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims + storage: 10Mi + # storageClassName: "" + # selector: + # matchLabels: + # release: "stable" + # Additional directory services to run. + # The 'model' and 'reader' services are always included. + services: + - writer + - importer + - exporter + + # [Optional] Sync from a remote directory. + # sync: + # address: "directory.prod.aserto.com:8443" + # # [Optional] API key for the remote directory + # apiKey: "" + # # [Optional] Kubernetes secret containing the API key for the remote directory + # apiKeySecret: + # # Secret name + # name: "" + # # Secret key + # key: "" + # # Skip verification of remote TLS certificate + # skipTLSVerification: false + # # The frequency of syncs in minutes. + # intervalMinutes: 1 + # # Request timeout + # timeoutSeconds: 5 + + # Use a remote directory instead running a local edge. + # If remote is specified, edge configuration is ignored. + # remote: + # # Remote directory address (e.g. directory.prod.aserto.com:8443) + # address: "" + # # [Optional] tenant ID for the remote directory + # tenantID: "" + # # [Optional] API key for the remote directory + # apiKey: "" + # # [Optional] Kubernetes secret containing the API key for the remote directory + # apiKeySecret: + # # Secret name + # name: "" + # # Secret key + # key: "" + # # [Optional] CA certificate for the remote directory + # caCert: | + # -----BEGIN CERTIFICATE----- + # ... + # -----END CERTIFICATE----- + # # [Optional] Kubernetes secret containing the CA certificate for the remote directory + # caCertSecret: + # name: "" + # key: "tls.crt" + # # [Optional] Skip verification of remote TLS certificate + # skipTLSVerification: false + # # [Optional] Request timeout + # timeoutSeconds: 5 + # # [Optional] Additional headers to include in requests to the remote directory + # additionalHeaders: + # "header-name": header-value + +# Acceptable clock skew for JWT validation. +jwtAcceptableSkewSeconds: 5 + +auth: + # [Optional] control access using API keys + apiKeys: + # keys can be specified directly + - key: a59692fa671e49a9a25861fd71472792 + # or as references to Kubernetes secrets + - secretName: topaz-api-key + secretKey: api-key + +ports: + grpc: 8282 + https: 8383 + health: 8484 + metrics: 8585 + +metrics: + enabled: true + zpages: true + +grpc: + connectionTimeoutSec: 2 + +console: + enabled: true + +http: + # if specified, the domain will automatically be added to the allowedOrigins list. + domain: "" + noTLS: false + readTimeout: 2s + readHeaderTimeout: 2s + writeTimeout: 2s + idleTimeout: 30s + allowedHeaders: + - Authorization + - Content-Type + - If-Match + - If-None-Match + - Depth + allowedMethods: + - GET + - POST + - HEAD + - DELETE + - PUT + - PATCH + - PROFIND + - MKCOL + - COPY + - MOVE + allowedOrigins: + - "{{ .Values.https.domain }}" + +# Override grpc and/or http settings per service. +serviceOverrides: + console: + # override http port and/or settings for a service. + # For example, to expose the console on port 8443 instead of 8383 and + # increase the read timeout for the console service: + http: + port: 8443 + readTimeout: 5s + model: + # override grpc port and/or settings for a service. + grpc: + port: 7272 + connectionTimeoutSec: 2 + +opa: + gracefuShutdownPeriodSeconds: 2 + maxPluginWaitTimeSeconds: 30 + # Persistent volume for bundles and discovery results. + persistence: + enabled: false + # PersistentVolumeClaim options. + # See https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims + storage: 10Mi + # storageClassName: "" + # selector: + # matchLabels: + # release: "stable" + policy: + oci: + registry: https://ghcr.io + image: "ghcr.io/aserto-policies/policy-rebac:latest" + user: "" + apiKey: "" + apiKeySecret: + name: "" + key: "" + serviceConfig: + # Additional OPA service configuration. + # See https://www.openpolicyagent.org/docs/latest/configuration/#services + response_header_timeout_seconds: 5 + # allow_insecure_tls: false + # headers: + # "header-name": header-value + bundleConfig: + # Additional OPA bundle configuration. + # See https://www.openpolicyagent.org/docs/latest/configuration/#bundles + polling: + min_delay_seconds: 60 + max_delay_seconds: 120 + # discovery: + # url: https://discovery.prod.aserto.com/api/v2/discovery + # policyName: "policy-name" + # apiKey: "1234567890" + # apiKeySecret: + # name: "discovery-api-key" + # key: "apiKey" + # serviceConfig: + # # Additional OPA service configuration. + # # See https://www.openpolicyagent.org/docs/latest/configuration/#services + # response_header_timeout_seconds: 5 + # allow_insecure_tls: false + # headers: + # "header-name": header-value + +# [Optional] +tenantID: "" + + +replicaCount: 1 + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Automatically mount a ServiceAccount's API credentials? + automount: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} +podLabels: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: + - path: / + pathType: ImplementationSpecific + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +livenessProbe: + httpGet: + path: / + port: http +readinessProbe: + httpGet: + path: / + port: http + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +# Additional volumes on the output Deployment definition. +volumes: [] +# - name: foo +# secret: +# secretName: mysecret +# optional: false + +# Additional volumeMounts on the output Deployment definition. +volumeMounts: [] +# - name: foo +# mountPath: "/etc/foo" +# readOnly: true + +nodeSelector: {} + +tolerations: [] + +affinity: {} From ed4bde58e67f5cbbd966014ee38d1e0e6bbb7378 Mon Sep 17 00:00:00 2001 From: Ronen Hilewicz Date: Thu, 26 Sep 2024 18:03:36 -0400 Subject: [PATCH 02/19] Clean up values.yaml and calculate allowed_origins --- charts/topaz/templates/_helpers.tpl | 9 +- charts/topaz/templates/config.yaml | 2 + charts/topaz/values.yaml | 147 ++++++++++++++++++---------- 3 files changed, 104 insertions(+), 54 deletions(-) diff --git a/charts/topaz/templates/_helpers.tpl b/charts/topaz/templates/_helpers.tpl index 611a0e8..49dba63 100644 --- a/charts/topaz/templates/_helpers.tpl +++ b/charts/topaz/templates/_helpers.tpl @@ -158,10 +158,13 @@ allowed_methods: {{- $cfg.allowedMethods | default list | toYaml | nindent 2 }} {{- end }} -{{- if $cfg.allowedOrigins }} -allowed_origins: -{{- $cfg.allowedOrigins | default list | toYaml | nindent 2 }} +{{- $origins := list "http://localhost:*" "https://localhost:*" }} +{{- if $cfg.domain }} +{{- $origins = append $origins $cfg.domain }} {{- end }} +{{- $origins = concat $origins ($cfg.additionalAllowedOrigins | default list) }} +allowed_origins: +{{- $origins | toYaml | nindent 2 }} {{- if $cfg.noTLS }} http: false diff --git a/charts/topaz/templates/config.yaml b/charts/topaz/templates/config.yaml index 5813e10..a140921 100644 --- a/charts/topaz/templates/config.yaml +++ b/charts/topaz/templates/config.yaml @@ -151,4 +151,6 @@ stringData: resource: {{ include "topaz.discoveryResource" . }} persist: {{ $.Values.opa.persistence.enabled | default "false" }} {{- end }} + {{- else }} + {{- fail "either opa.policy.discovery or opa.policy.oci must be set"}} {{- end }} diff --git a/charts/topaz/values.yaml b/charts/topaz/values.yaml index bca9651..f6700b9 100644 --- a/charts/topaz/values.yaml +++ b/charts/topaz/values.yaml @@ -14,6 +14,11 @@ logLevel: info # Set gRPC log level (trace/debug/info/warn/error) grpcLogLevel: info +# Web console configuration. +console: + # Enable the web console. + enabled: true + # Directory configuration. # Using a local directory by default. directory: @@ -39,7 +44,7 @@ directory: - exporter # [Optional] Sync from a remote directory. - # sync: + sync: {} # address: "directory.prod.aserto.com:8443" # # [Optional] API key for the remote directory # apiKey: "" @@ -58,7 +63,7 @@ directory: # Use a remote directory instead running a local edge. # If remote is specified, edge configuration is ignored. - # remote: + remote: {} # # Remote directory address (e.g. directory.prod.aserto.com:8443) # address: "" # # [Optional] tenant ID for the remote directory @@ -100,36 +105,49 @@ auth: - secretName: topaz-api-key secretKey: api-key +# Port configuration. +# The grpc and http ports can be overriden per service in the serviceOverrides section below. ports: grpc: 8282 https: 8383 health: 8484 metrics: 8585 +# Metrics configuration metrics: + # Enable metrics. enabled: true + # Expose zpages UI for grpc metrics. + # The pages are available at /debug/tracez and /debug/rpcz. zpages: true +# Global gRPC configuration. +# These settings can be overridden per service in serviceOverrides below. grpc: connectionTimeoutSec: 2 -console: - enabled: true - +# Global configuration of the console and REST APIs. +# These settings can be overridden per service in serviceOverrides below. http: # if specified, the domain will automatically be added to the allowedOrigins list. + # e.g. 'domain: https://topaz.example.com:8383' domain: "" + # if true, services are exposed over HTTP instead of HTTPS. noTLS: false + # HTTP server timeouts. + # See https://golang.org/pkg/net/http/#Server readTimeout: 2s readHeaderTimeout: 2s writeTimeout: 2s idleTimeout: 30s + # CORS allowed headers allowedHeaders: - Authorization - Content-Type - If-Match - If-None-Match - Depth + # CORS allowed methods allowedMethods: - GET - POST @@ -141,24 +159,28 @@ http: - MKCOL - COPY - MOVE - allowedOrigins: - - "{{ .Values.https.domain }}" + # Additional allowed origins. + # https://localhost:* is always allowed and if 'domain' is specified, + # it is also automatically added. + additionalAllowedOrigins: [] # Override grpc and/or http settings per service. -serviceOverrides: - console: - # override http port and/or settings for a service. - # For example, to expose the console on port 8443 instead of 8383 and - # increase the read timeout for the console service: - http: - port: 8443 - readTimeout: 5s - model: - # override grpc port and/or settings for a service. - grpc: - port: 7272 - connectionTimeoutSec: 2 - +serviceOverrides: {} +# # Examples: +# console: +# # override http port and read timeout for the console service. +# # For example, to expose the console on port 8443 instead of 8383 and +# # increase the read timeout for the console service: +# http: +# port: 8443 +# readTimeout: 5s +# model: +# # override grpc port and connection timeout settings for the model service. +# grpc: +# port: 7272 +# connectionTimeoutSec: 2 + +# OPA configuration opa: gracefuShutdownPeriodSeconds: 2 maxPluginWaitTimeSeconds: 30 @@ -173,46 +195,69 @@ opa: # matchLabels: # release: "stable" policy: - oci: - registry: https://ghcr.io - image: "ghcr.io/aserto-policies/policy-rebac:latest" - user: "" - apiKey: "" - apiKeySecret: - name: "" - key: "" - serviceConfig: - # Additional OPA service configuration. - # See https://www.openpolicyagent.org/docs/latest/configuration/#services - response_header_timeout_seconds: 5 - # allow_insecure_tls: false - # headers: - # "header-name": header-value - bundleConfig: - # Additional OPA bundle configuration. - # See https://www.openpolicyagent.org/docs/latest/configuration/#bundles - polling: - min_delay_seconds: 60 - max_delay_seconds: 120 - # discovery: + # The 'oci' and 'discovery' fields are mutually exclusive. + # Exactly one of them must be specified. + + # Run policy from an OCI registry. + oci: {} + # # OCI registry URL. + # registry: https://ghcr.io + # # Policy image URI. + # image: "ghcr.io/aserto-policies/policy-rebac:latest" + # # [Optional] OCI registry user name. + # # Note: Some registries including ghcr.io require that the user name is left empty + # # when using a personal access token as the API key. + # user: "" + # # [Optional] OCI registry password, token, or API key. + # apiKey: "" + # # [Optional] Kubernetes secret containing the OCI registry password, token, or API key. + # apiKeySecret: + # # Secret name + # name: "" + # # Secret key + # key: "" + # # Additional OPA service configuration. + # # See https://www.openpolicyagent.org/docs/latest/configuration/#services + # serviceConfig: + # response_header_timeout_seconds: 5 + # # allow_insecure_tls: false + # # headers: + # # "header-name": header-value + # # Additional OPA bundle configuration. + # # See https://www.openpolicyagent.org/docs/latest/configuration/#bundles + # bundleConfig: + # polling: + # min_delay_seconds: 60 + # max_delay_seconds: 120 + + # Retrieve policy configuration from a discovery service. + discovery: {} + # # Discovery service URL. # url: https://discovery.prod.aserto.com/api/v2/discovery + # # Name of policy to run. # policyName: "policy-name" - # apiKey: "1234567890" + # # [Optional] Discovery service API key. + # apiKey: "" + # # [Optional] Kubernetes secret containing the discovery service API key. # apiKeySecret: - # name: "discovery-api-key" - # key: "apiKey" + # # Secret name + # name: "" + # # Secret key + # key: "" # serviceConfig: # # Additional OPA service configuration. # # See https://www.openpolicyagent.org/docs/latest/configuration/#services # response_header_timeout_seconds: 5 - # allow_insecure_tls: false - # headers: - # "header-name": header-value + # # allow_insecure_tls: false + # # headers: + # # "header-name": header-value -# [Optional] -tenantID: "" +# [Optional] ID of the tenant that owns the policy. +# This is required when running a policy from a discovery service. +tenantID: "" +# Standard Kubernetes configuration replicaCount: 1 imagePullSecrets: [] From 02428d0bfab9aa304bc0cd637f5f93ebb97921f8 Mon Sep 17 00:00:00 2001 From: Ronen Hilewicz Date: Fri, 27 Sep 2024 11:46:34 -0400 Subject: [PATCH 03/19] Volumes --- charts/topaz/templates/_helpers.tpl | 49 ++++++++----- charts/topaz/templates/config.yaml | 39 ++++++----- charts/topaz/templates/deployment.yaml | 77 ++++++++++++++++++-- charts/topaz/templates/pvc-db.yaml | 21 ++++++ charts/topaz/templates/pvc-policy.yaml | 22 ++++++ charts/topaz/values.yaml | 97 ++++++++++++++------------ 6 files changed, 218 insertions(+), 87 deletions(-) create mode 100644 charts/topaz/templates/pvc-db.yaml create mode 100644 charts/topaz/templates/pvc-policy.yaml diff --git a/charts/topaz/templates/_helpers.tpl b/charts/topaz/templates/_helpers.tpl index 49dba63..ee31c4a 100644 --- a/charts/topaz/templates/_helpers.tpl +++ b/charts/topaz/templates/_helpers.tpl @@ -65,22 +65,24 @@ Create the name of the service account to use Remote directory configuration */}} {{- define "topaz.remoteDirectory" -}} -address: {{ ((.Values.directory).remote).address }} -{{- if not (empty ((.Values.directory).remote).tenantID) }} -tenant_id: {{ ((.Values.directory).remote).tenantID }} +{{- with (.Values.directory).remote -}} +address: {{ .address }} +{{- if not (empty .tenantID) }} +tenant_id: {{ .tenantID }} {{- end }} -{{- if not (empty ((.Values.directory).remote).apiKey) }} -api_key: {{ ((.Values.directory).remote).apiKey }} +{{- if not (empty .apiKey) }} +api_key: {{ .apiKey }} {{- end }} -{{- if ((.Values.directory).remote).skipTLSVerification }} +{{- if .skipTLSVerification }} insecure: true {{- end }} -{{- if not (empty ((.Values.directory).remote).caCert | and (empty ((.Values.directory).remote).caCertSecret)) }} +{{- if not (empty .caCert | and (empty .caCertSecret)) }} ca_cert_path: /directory-certs/ca.crt {{- end }} -{{- if not (empty ((.Values.directory).remote).additionalHeaders) }} +{{- if not (empty .additionalHeaders) }} headers: - {{ toYaml ((.Values.directory).remote).additionalHeaders | toYaml | nindent 2 }} + {{ toYaml .additionalHeaders | toYaml | nindent 2 }} +{{- end }} {{- end }} {{- end }} @@ -88,7 +90,7 @@ headers: Topaz API key configuration */}} {{- define "topaz.apiKeys" -}} -{{- range .Values.auth.apiKeys }} +{{- range (.Values.auth).apiKeys }} {{- if .key -}} "{{ .key }}": root-key {{- else if .secretName -}} @@ -99,6 +101,19 @@ Topaz API key configuration {{- end }} {{- end }} +{{- define "topaz.apiKeyVolumes" -}} +{{- range (.Values.auth).apiKeys -}} +{{- if .secretName -}} +{{- $secretKey := .secretKey | default "api-key" -}} +- name: {{ printf "API_KEY_%s_%s" .secretName $secretKey | upper | replace "-" "_" }} + valueFrom: + secretKeyRef: + name: {{ .secretName }} + key: {{ $secretKey }} +{{- end }} +{{- end }} +{{- end }} + {{- define "topaz.discoveryKey" -}} {{- if .apiKey -}} {{- .apiKey }} @@ -120,11 +135,11 @@ Topaz API key configuration {{- end }} {{- define "topaz.svcDependencies" -}} -{{- $deps := dict "reader" "model" "writer" "model" "importer" "model" "authorizer" "reader" "console" "authorizer" }} -{{- $dep := get $deps .service }} +{{- $deps := dict "reader" "model" "writer" "model" "importer" "model" "authorizer" "reader" "console" "authorizer" -}} +{{- $dep := get $deps .service -}} {{- if $dep -}} needs: - - {{ $dep }} + - {{ $dep }} {{- end }} {{- end }} @@ -133,7 +148,7 @@ needs: {{- $svc := last . -}} {{- $global := $values.http -}} {{- $cfg := merge (dig $svc "grpc" dict $values.serviceOverrides) $values.grpc -}} -listen_address: 0.0.0.0:{{ $cfg.port | default "8282" }} +listen_address: 0.0.0.0:{{ ($values.ports).grpc | default "8282" }} connection_timeout_seconds: {{ $cfg.connectionTimeoutSec | default "2" }} {{- end }} @@ -142,7 +157,7 @@ connection_timeout_seconds: {{ $cfg.connectionTimeoutSec | default "2" }} {{- $values := first . -}} {{- $svc := last . -}} {{- $cfg := merge (dig $svc "http" dict $values.serviceOverrides) $values.http -}} -listen_address: 0.0.0.0:{{ $cfg.port | default "8383" }} +listen_address: 0.0.0.0:{{ ($values.ports).https | default "8383" }} {{- if $cfg.domain }} fdqn: {{ $cfg.domain }} @@ -181,9 +196,9 @@ idle_timeout: {{ $cfg.idleTimeout | default "30s" }} {{- define "topaz.enabledServices" -}} {{- $services := list "authorizer" "model" "reader" | - concat (((.Values.directory).edge).services | default list) }} + concat (((.Values.directory).edge).services | default list) }} {{- if .Values.console.enabled }} -{{- $services = append $services "console" }} + {{- $services = append $services "console" }} {{- end }} {{- $services | toJson }} {{- end }} diff --git a/charts/topaz/templates/config.yaml b/charts/topaz/templates/config.yaml index a140921..d3a77cf 100644 --- a/charts/topaz/templates/config.yaml +++ b/charts/topaz/templates/config.yaml @@ -18,14 +18,15 @@ stringData: {{ if empty ((.Values.directory).remote).address -}} directory: - db_path: '${TOPAZ_DB_DIR}/directory.db' + db_path: /db/directory.db request_timeout: {{ ((.Values.directory).edge).openTimeout | default "5s" }} - # TODO: apply 'reader' configuration remote_directory: - address: 0.0.0.0:9292 - api_key: "TODO: use reader key if configured" - ca_cert_path: "TODO: point to topaz CA cert" + address: 0.0.0.0:{{ (.Values.ports).grpc | default "8282" }} + {{- if (.Values.auth).apiKeys }} + api_key: {{ include "topaz.apiKeys" . | fromYaml | keys | first }} + {{- end }} + ca_cert_path: /grpc-certs/grpc-ca.crt timeout_in_seconds: {{ ((.Values.directory).remote).timeoutSeconds | default "5" }} {{- else -}} remote_directory: @@ -58,37 +59,37 @@ stringData: health: listen_address: 0.0.0.0:{{ include "aserto-lib.healthPort" . }} certs: - tls_key_path: '${TOPAZ_CERTS_DIR}/gateway.key' - tls_cert_path: '${TOPAZ_CERTS_DIR}/gateway.crt' - tls_ca_cert_path: '${TOPAZ_CERTS_DIR}/gateway-ca.crt' + tls_key_path: /https-certs/gateway.key + tls_cert_path: /http-certs/gateway.crt + tls_ca_cert_path: /http-certs/gateway-ca.crt {{- if (.Values.metrics).enabled }} metrics: {{- include "aserto-lib.metricsService" . | nindent 8 }} certs: - tls_key_path: '${TOPAZ_CERTS_DIR}/gateway.key' - tls_cert_path: '${TOPAZ_CERTS_DIR}/gateway.crt' - tls_ca_cert_path: '${TOPAZ_CERTS_DIR}/gateway-ca.crt' + tls_key_path: /https-certs/gateway.key + tls_cert_path: /http-certs/gateway.crt + tls_ca_cert_path: /http-certs/gateway-ca.crt {{- end }} services: {{- range (include "topaz.enabledServices" . | fromJsonArray) }} {{ . }}: - {{- include "topaz.svcDependencies" (dict "service" .) | nindent 10 }} - {{- if not (eq . "console") }} + {{- include "topaz.svcDependencies" (dict "service" .) | nindent 10 -}} + {{- if not (eq . "console") -}} grpc: {{- include "topaz.grpcService" (list $.Values .) | nindent 12 }} certs: - tls_key_path: '${TOPAZ_CERTS_DIR}/grpc.key' - tls_cert_path: '${TOPAZ_CERTS_DIR}/grpc.crt' - tls_ca_cert_path: '${TOPAZ_CERTS_DIR}/grpc-ca.crt' + tls_key_path: /grpc-certs/grpc.key + tls_cert_path: /grpc-certs/grpc.crt + tls_ca_cert_path: /grpc-certs/grpc-ca.crt {{- end }} gateway: {{- include "topaz.gatewayService" (list $.Values .) | nindent 12 }} certs: - tls_key_path: '${TOPAZ_CERTS_DIR}/gateway.key' - tls_cert_path: '${TOPAZ_CERTS_DIR}/gateway.crt' - tls_ca_cert_path: '${TOPAZ_CERTS_DIR}/gateway-ca.crt' + tls_key_path: /https-certs/gateway.key + tls_cert_path: /http-certs/gateway.crt + tls_ca_cert_path: /http-certs/gateway-ca.crt {{- end }} opa: diff --git a/charts/topaz/templates/deployment.yaml b/charts/topaz/templates/deployment.yaml index 5871204..c80fe55 100644 --- a/charts/topaz/templates/deployment.yaml +++ b/charts/topaz/templates/deployment.yaml @@ -1,5 +1,5 @@ apiVersion: apps/v1 -kind: Deployment +kind: StatefulSet metadata: name: {{ include "topaz.fullname" . }} labels: @@ -37,21 +37,86 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: + - name: grpc + containerPort: {{ (.Values.ports).grpc | default 8282 }} + protocol: TCP - name: http - containerPort: {{ .Values.service.port }} + containerPort: {{ (.Values.ports).https | default 8383 }} + protocol: TCP + - name: health + containerPort: {{ (.Values.ports).health | default 8484 }} + protocol: TCP + {{- if (.Values.metrics).enabled }} + - name: health + containerPort: {{ (.Values.ports).metrics | default 8585 }} protocol: TCP + {{- end }} livenessProbe: {{- toYaml .Values.livenessProbe | nindent 12 }} readinessProbe: {{- toYaml .Values.readinessProbe | nindent 12 }} resources: {{- toYaml .Values.resources | nindent 12 }} - {{- with .Values.volumeMounts }} volumeMounts: - {{- toYaml . | nindent 12 }} - {{- end }} - {{- with .Values.volumes }} + - name: config + mountPath: /config + readOnly: true + - name: db + mountPath: /db + readOnly: false + - name: opa + mountPath: /opa-persistence + readOnly: false + - name: grpc-certs + mountPath: /grpc-certs + {{- if (.Values.certs).grpc }} + readOnly: true + {{- end }} + - name: https-certs + mountPath: /https-certs + {{- if (.Values.certs).https }} + readOnly: true + {{- end }} + {{- with .Values.volumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} volumes: + - name: config + secret: + secretName: {{ include "topaz.fullname" . }}-config + items: + - key: config.yaml + path: config.yaml + - name: grpc-certs + {{- with (.Values.certs).grpc }} + secret: + secretName: {{ . }} + {{- else }} + emptyDir: {} + {{- end }} + - name: https-certs + {{- with (.Values.certs).https }} + secret: + secretName: {{ . }} + {{- else }} + emptyDir: {} + {{- end }} + - name: db + {{- if empty (.Values.directory).remote | and (((.Values.directory).edge).persistence).enabled }} + persistentVolumeClaim: + claimName: pvc-db + {{- else }} + emptyDir: {} + {{- end }} + - name: opa + {{- if ((.Values.opa).persistence).enabled }} + persistentVolumeClaim: + claimName: pvc-policy + {{- else }} + emptyDir: {} + {{- end }} + {{- include "topaz.apiKeyVolumes" . | nindent 8 }} + {{- with .Values.volumes }} {{- toYaml . | nindent 8 }} {{- end }} {{- with .Values.nodeSelector }} diff --git a/charts/topaz/templates/pvc-db.yaml b/charts/topaz/templates/pvc-db.yaml new file mode 100644 index 0000000..e815b3e --- /dev/null +++ b/charts/topaz/templates/pvc-db.yaml @@ -0,0 +1,21 @@ +{{- if empty (.Values.directory).remote | and (((.Values.directory).edge).persistence).enabled }} +{{- with ((.Values.directory).edge).persistence }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: pvc-db +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .storage | default "1Gi" }} + {{- if .storageClassName }} + storageClassName: {{ .storageClassName }} + {{- end }} + {{- if .selector }} + selector: + {{- .selector | toYaml | nindent 4 }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/topaz/templates/pvc-policy.yaml b/charts/topaz/templates/pvc-policy.yaml new file mode 100644 index 0000000..54d6de9 --- /dev/null +++ b/charts/topaz/templates/pvc-policy.yaml @@ -0,0 +1,22 @@ +{{- if ((.Values.opa).persistence).enabled }} +{{- with (.Values.opa).persistence }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: pvc-policy +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .storage | default "10Mi" }} + {{- if .storageClassName }} + storageClassName: {{ .storageClassName }} + {{- end }} + {{- if .selector }} + selector: + {{- .selector | toYaml | nindent 4 }} + {{- end }} +{{- end }} +{{- end }} + diff --git a/charts/topaz/values.yaml b/charts/topaz/values.yaml index f6700b9..488610a 100644 --- a/charts/topaz/values.yaml +++ b/charts/topaz/values.yaml @@ -28,10 +28,10 @@ directory: openTimeout: 5s # Persistent volume for the local directory. persistence: - enabled: false + enabled: true # PersistentVolumeClaim options. # See https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims - storage: 10Mi + storage: 1Gi # storageClassName: "" # selector: # matchLabels: @@ -113,6 +113,14 @@ ports: health: 8484 metrics: 8585 +# [Optional] cutsom TLS certificates for the gRPC and HTTPS servers. +# If not provided, topaz generates self-signed certificates. +# To use your own certificates provide the names of secrets +# of type kubernetes.io/tls +certs: {} + # grpc: topaz-grpc-cert + # https: topaz-https-cert + # Metrics configuration metrics: # Enable metrics. @@ -168,16 +176,13 @@ http: serviceOverrides: {} # # Examples: # console: -# # override http port and read timeout for the console service. -# # For example, to expose the console on port 8443 instead of 8383 and -# # increase the read timeout for the console service: +# # override http and read timeout for the console service. +# # For example,to increase the read timeout for the console service: # http: -# port: 8443 # readTimeout: 5s # model: -# # override grpc port and connection timeout settings for the model service. +# # override grpc connection timeout settings for the model service. # grpc: -# port: 7272 # connectionTimeoutSec: 2 # OPA configuration @@ -199,36 +204,36 @@ opa: # Exactly one of them must be specified. # Run policy from an OCI registry. - oci: {} - # # OCI registry URL. - # registry: https://ghcr.io - # # Policy image URI. - # image: "ghcr.io/aserto-policies/policy-rebac:latest" - # # [Optional] OCI registry user name. - # # Note: Some registries including ghcr.io require that the user name is left empty - # # when using a personal access token as the API key. - # user: "" - # # [Optional] OCI registry password, token, or API key. - # apiKey: "" - # # [Optional] Kubernetes secret containing the OCI registry password, token, or API key. - # apiKeySecret: - # # Secret name - # name: "" - # # Secret key - # key: "" - # # Additional OPA service configuration. - # # See https://www.openpolicyagent.org/docs/latest/configuration/#services - # serviceConfig: - # response_header_timeout_seconds: 5 - # # allow_insecure_tls: false - # # headers: - # # "header-name": header-value - # # Additional OPA bundle configuration. - # # See https://www.openpolicyagent.org/docs/latest/configuration/#bundles - # bundleConfig: - # polling: - # min_delay_seconds: 60 - # max_delay_seconds: 120 + oci: + # OCI registry URL. + registry: https://ghcr.io + # Policy image URI. + image: "ghcr.io/aserto-policies/policy-rebac:latest" + # [Optional] OCI registry user name. + # Note: Some registries including ghcr.io require that the user name is left empty + # when using a personal access token as the API key. + user: "" + # [Optional] OCI registry password, token, or API key. + apiKey: "" + # [Optional] Kubernetes secret containing the OCI registry password, token, or API key. + apiKeySecret: + # Secret name + name: "" + # Secret key + key: "" + # Additional OPA service configuration. + # See https://www.openpolicyagent.org/docs/latest/configuration/#services + serviceConfig: + response_header_timeout_seconds: 5 + # allow_insecure_tls: false + # headers: + # "header-name": header-value + # Additional OPA bundle configuration. + # See https://www.openpolicyagent.org/docs/latest/configuration/#bundles + bundleConfig: + polling: + min_delay_seconds: 60 + max_delay_seconds: 120 # Retrieve policy configuration from a discovery service. discovery: {} @@ -291,7 +296,6 @@ securityContext: {} service: type: ClusterIP - port: 80 ingress: enabled: false @@ -322,13 +326,16 @@ resources: {} # memory: 128Mi livenessProbe: - httpGet: - path: / - port: http + grpc: + port: health + failureThreshold: 1 + periodSeconds: 10 + readinessProbe: - httpGet: - path: / - port: http + grpc: + port: health + initialDelaySeconds: 5 + periodSeconds: 5 autoscaling: enabled: false From 8f0a0b6cc1341ed0b35f54294d6a522696df4c3b Mon Sep 17 00:00:00 2001 From: Ronen Hilewicz Date: Fri, 27 Sep 2024 13:45:58 -0400 Subject: [PATCH 04/19] Remote directory CA cert --- charts/topaz/templates/_helpers.tpl | 19 +++++- charts/topaz/templates/config.yaml | 25 ++++--- .../topaz/templates/configmap-remote-ca.yaml | 10 +++ charts/topaz/templates/deployment.yaml | 3 + charts/topaz/values.yaml | 68 +++++++++---------- 5 files changed, 76 insertions(+), 49 deletions(-) create mode 100644 charts/topaz/templates/configmap-remote-ca.yaml diff --git a/charts/topaz/templates/_helpers.tpl b/charts/topaz/templates/_helpers.tpl index ee31c4a..3bf8387 100644 --- a/charts/topaz/templates/_helpers.tpl +++ b/charts/topaz/templates/_helpers.tpl @@ -77,11 +77,26 @@ api_key: {{ .apiKey }} insecure: true {{- end }} {{- if not (empty .caCert | and (empty .caCertSecret)) }} -ca_cert_path: /directory-certs/ca.crt +ca_cert_path: /directory-certs/{{ (.caCertSecret).key | default "tls.crt" }} {{- end }} {{- if not (empty .additionalHeaders) }} headers: - {{ toYaml .additionalHeaders | toYaml | nindent 2 }} + {{- toYaml .additionalHeaders | toYaml | nindent 2 }} +{{- end }} +{{- end }} +{{- end }} + +{{- define "topaz.remoteDirectoryCertVolume" -}} +{{- $name := printf "%s-remote-ca" (include "topaz.fullname" .) -}} +{{- with (.Values.directory).remote -}} +{{- if .caCert -}} +- name: remote-certs + configMap: + name: {{ $name }} +{{- else if (.caCertSecret).name -}} +- name: remote-certs + secret: + secretName: {{ $name }} {{- end }} {{- end }} {{- end }} diff --git a/charts/topaz/templates/config.yaml b/charts/topaz/templates/config.yaml index d3a77cf..55d70a6 100644 --- a/charts/topaz/templates/config.yaml +++ b/charts/topaz/templates/config.yaml @@ -36,7 +36,6 @@ stringData: jwt: acceptable_time_skew_seconds: {{ .Values.jwtAcceptableSkewSeconds | default "5"}} - # authentication configuration auth: {{- if not (empty (.Values.auth).apiKeys) }} api_keys: @@ -59,17 +58,17 @@ stringData: health: listen_address: 0.0.0.0:{{ include "aserto-lib.healthPort" . }} certs: - tls_key_path: /https-certs/gateway.key - tls_cert_path: /http-certs/gateway.crt - tls_ca_cert_path: /http-certs/gateway-ca.crt + tls_key_path: /https-certs/tls.key + tls_cert_path: /http-certs/tls.crt + tls_ca_cert_path: /http-certs/ca.crt {{- if (.Values.metrics).enabled }} metrics: {{- include "aserto-lib.metricsService" . | nindent 8 }} certs: - tls_key_path: /https-certs/gateway.key - tls_cert_path: /http-certs/gateway.crt - tls_ca_cert_path: /http-certs/gateway-ca.crt + tls_key_path: /https-certs/tls.key + tls_cert_path: /http-certs/tls.crt + tls_ca_cert_path: /http-certs/ca.crt {{- end }} services: @@ -80,16 +79,16 @@ stringData: grpc: {{- include "topaz.grpcService" (list $.Values .) | nindent 12 }} certs: - tls_key_path: /grpc-certs/grpc.key - tls_cert_path: /grpc-certs/grpc.crt - tls_ca_cert_path: /grpc-certs/grpc-ca.crt + tls_key_path: /grpc-certs/tls.key + tls_cert_path: /grpc-certs/tls.crt + tls_ca_cert_path: /grpc-certs/ca.crt {{- end }} gateway: {{- include "topaz.gatewayService" (list $.Values .) | nindent 12 }} certs: - tls_key_path: /https-certs/gateway.key - tls_cert_path: /http-certs/gateway.crt - tls_ca_cert_path: /http-certs/gateway-ca.crt + tls_key_path: /https-certs/tls.key + tls_cert_path: /http-certs/tls.crt + tls_ca_cert_path: /http-certs/ca.crt {{- end }} opa: diff --git a/charts/topaz/templates/configmap-remote-ca.yaml b/charts/topaz/templates/configmap-remote-ca.yaml new file mode 100644 index 0000000..68e929c --- /dev/null +++ b/charts/topaz/templates/configmap-remote-ca.yaml @@ -0,0 +1,10 @@ +{{- if ((.Values.directory).remote).caCert }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "topaz.fullname" . }}-remote-ca +data: + tls.crt: | + {{- .Values.directory.remote.caCert | nindent 4 }} +{{- end }} diff --git a/charts/topaz/templates/deployment.yaml b/charts/topaz/templates/deployment.yaml index c80fe55..5b02302 100644 --- a/charts/topaz/templates/deployment.yaml +++ b/charts/topaz/templates/deployment.yaml @@ -101,6 +101,9 @@ spec: {{- else }} emptyDir: {} {{- end }} + {{- if ((.Values.directory).remote).address -}} + {{ include "topaz.remoteDirectoryCertVolume" . | nindent 8 }} + {{- end }} - name: db {{- if empty (.Values.directory).remote | and (((.Values.directory).edge).persistence).enabled }} persistentVolumeClaim: diff --git a/charts/topaz/values.yaml b/charts/topaz/values.yaml index 488610a..dff97f2 100644 --- a/charts/topaz/values.yaml +++ b/charts/topaz/values.yaml @@ -64,46 +64,46 @@ directory: # Use a remote directory instead running a local edge. # If remote is specified, edge configuration is ignored. remote: {} - # # Remote directory address (e.g. directory.prod.aserto.com:8443) - # address: "" - # # [Optional] tenant ID for the remote directory - # tenantID: "" - # # [Optional] API key for the remote directory - # apiKey: "" - # # [Optional] Kubernetes secret containing the API key for the remote directory - # apiKeySecret: - # # Secret name - # name: "" - # # Secret key - # key: "" - # # [Optional] CA certificate for the remote directory - # caCert: | - # -----BEGIN CERTIFICATE----- - # ... - # -----END CERTIFICATE----- - # # [Optional] Kubernetes secret containing the CA certificate for the remote directory - # caCertSecret: - # name: "" - # key: "tls.crt" - # # [Optional] Skip verification of remote TLS certificate - # skipTLSVerification: false - # # [Optional] Request timeout - # timeoutSeconds: 5 - # # [Optional] Additional headers to include in requests to the remote directory - # additionalHeaders: - # "header-name": header-value + # # Remote directory address (e.g. directory.prod.aserto.com:8443) + # address: "" + # # [Optional] tenant ID for the remote directory + # tenantID: "" + # # [Optional] API key for the remote directory + # apiKey: "" + # # [Optional] Kubernetes secret containing the API key for the remote directory + # apiKeySecret: + # # Secret name + # name: "" + # # Secret key + # key: "" + # # [Optional] CA certificate for the remote directory + # caCert: | + # -----BEGIN CERTIFICATE----- + # ... + # -----END CERTIFICATE----- + # # [Optional] Kubernetes secret containing the CA certificate for the remote directory + # caCertSecret: + # name: "" + # key: "" + # # [Optional] Skip verification of remote TLS certificate + # skipTLSVerification: false + # # [Optional] Request timeout + # timeoutSeconds: 5 + # # [Optional] Additional headers to include in requests to the remote directory + # additionalHeaders: + # "header-name": header-value # Acceptable clock skew for JWT validation. jwtAcceptableSkewSeconds: 5 auth: # [Optional] control access using API keys - apiKeys: - # keys can be specified directly - - key: a59692fa671e49a9a25861fd71472792 - # or as references to Kubernetes secrets - - secretName: topaz-api-key - secretKey: api-key + # apiKeys: + # # keys can be specified directly + # - key: a59692fa671e49a9a25861fd71472792 + # # or as references to Kubernetes secrets + # - secretName: topaz-api-key + # secretKey: api-key # Port configuration. # The grpc and http ports can be overriden per service in the serviceOverrides section below. From 035ca6924b13170530d534c3b2e9e9ba4efb645f Mon Sep 17 00:00:00 2001 From: Ronen Hilewicz Date: Fri, 27 Sep 2024 16:25:30 -0400 Subject: [PATCH 05/19] Service ports, bugfixes, and disable health probes --- charts/topaz/templates/_helpers.tpl | 6 +++--- charts/topaz/templates/config.yaml | 18 ++++++++---------- charts/topaz/templates/deployment.yaml | 16 +++++++++++----- charts/topaz/templates/service.yaml | 16 +++++++++++++++- charts/topaz/values.yaml | 4 ---- 5 files changed, 37 insertions(+), 23 deletions(-) diff --git a/charts/topaz/templates/_helpers.tpl b/charts/topaz/templates/_helpers.tpl index 3bf8387..b578b1a 100644 --- a/charts/topaz/templates/_helpers.tpl +++ b/charts/topaz/templates/_helpers.tpl @@ -140,11 +140,11 @@ Topaz API key configuration {{- end }} {{- define "topaz.ociCredentials" -}} -{{- if .apiKeySecret -}} +{{- if (.apiKeySecret).name -}} "${REGISTRY_API_KEY}" -{{- else if .user }} +{{- else if .user -}} {{ printf "%s:%s" .user .apiKey }} -{{- else }} +{{- else -}} {{ .apiKey }} {{- end }} {{- end }} diff --git a/charts/topaz/templates/config.yaml b/charts/topaz/templates/config.yaml index 55d70a6..9119f40 100644 --- a/charts/topaz/templates/config.yaml +++ b/charts/topaz/templates/config.yaml @@ -59,36 +59,34 @@ stringData: listen_address: 0.0.0.0:{{ include "aserto-lib.healthPort" . }} certs: tls_key_path: /https-certs/tls.key - tls_cert_path: /http-certs/tls.crt - tls_ca_cert_path: /http-certs/ca.crt + tls_cert_path: /https-certs/tls.crt + tls_ca_cert_path: /https-certs/ca.crt {{- if (.Values.metrics).enabled }} metrics: {{- include "aserto-lib.metricsService" . | nindent 8 }} certs: tls_key_path: /https-certs/tls.key - tls_cert_path: /http-certs/tls.crt - tls_ca_cert_path: /http-certs/ca.crt + tls_cert_path: /https-certs/tls.crt + tls_ca_cert_path: /https-certs/ca.crt {{- end }} services: {{- range (include "topaz.enabledServices" . | fromJsonArray) }} {{ . }}: - {{- include "topaz.svcDependencies" (dict "service" .) | nindent 10 -}} - {{- if not (eq . "console") -}} + {{- include "topaz.svcDependencies" (dict "service" .) | nindent 10 }} grpc: {{- include "topaz.grpcService" (list $.Values .) | nindent 12 }} certs: tls_key_path: /grpc-certs/tls.key tls_cert_path: /grpc-certs/tls.crt tls_ca_cert_path: /grpc-certs/ca.crt - {{- end }} gateway: {{- include "topaz.gatewayService" (list $.Values .) | nindent 12 }} certs: tls_key_path: /https-certs/tls.key - tls_cert_path: /http-certs/tls.crt - tls_ca_cert_path: /http-certs/ca.crt + tls_cert_path: /https-certs/tls.crt + tls_ca_cert_path: /https-certs/ca.crt {{- end }} opa: @@ -110,7 +108,7 @@ stringData: oci: type: oci url: {{ .registry | required "opa.policy.oci.registry is required" }} - {{- if (.apiKey | or .apiKeySecret) }} + {{- if (.apiKey | or (.apiKeySecret).name) }} credentials: bearer: scheme: basic diff --git a/charts/topaz/templates/deployment.yaml b/charts/topaz/templates/deployment.yaml index 5b02302..1616e2a 100644 --- a/charts/topaz/templates/deployment.yaml +++ b/charts/topaz/templates/deployment.yaml @@ -38,23 +38,29 @@ spec: imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - name: grpc - containerPort: {{ (.Values.ports).grpc | default 8282 }} + containerPort: {{ (.Values.ports).grpc | default "8282" }} protocol: TCP - name: http - containerPort: {{ (.Values.ports).https | default 8383 }} + containerPort: {{ (.Values.ports).https | default "8383" }} protocol: TCP - name: health - containerPort: {{ (.Values.ports).health | default 8484 }} + containerPort: {{ (.Values.ports).health | default "8484" }} protocol: TCP {{- if (.Values.metrics).enabled }} - - name: health - containerPort: {{ (.Values.ports).metrics | default 8585 }} + - name: metrics + containerPort: {{ (.Values.ports).metrics | default "8585" }} protocol: TCP {{- end }} + {{/* livenessProbe: + grpc: + port: {{ (.Values.ports).health | default "8484" }} {{- toYaml .Values.livenessProbe | nindent 12 }} readinessProbe: + grpc: + port: {{ (.Values.ports).health | default "8484" }} {{- toYaml .Values.readinessProbe | nindent 12 }} + */}} resources: {{- toYaml .Values.resources | nindent 12 }} volumeMounts: diff --git a/charts/topaz/templates/service.yaml b/charts/topaz/templates/service.yaml index dd8a176..f847663 100644 --- a/charts/topaz/templates/service.yaml +++ b/charts/topaz/templates/service.yaml @@ -7,9 +7,23 @@ metadata: spec: type: {{ .Values.service.type }} ports: - - port: {{ .Values.service.port }} + - port: {{ (.Values.ports).grpc | default "8282" }} + targetPort: grpc + protocol: TCP + name: grpc + - port: {{ (.Values.ports).https | default "8383" }} targetPort: http protocol: TCP name: http + - port: {{ (.Values.ports).health | default "8484" }} + targetPort: health + protocol: TCP + name: health + {{- if (.Values.metrics).enabled }} + - port: {{ (.Values.ports).metrics | default "8585" }} + targetPort: metrics + protocol: TCP + name: metrics + {{- end }} selector: {{- include "topaz.selectorLabels" . | nindent 4 }} diff --git a/charts/topaz/values.yaml b/charts/topaz/values.yaml index dff97f2..dea6b54 100644 --- a/charts/topaz/values.yaml +++ b/charts/topaz/values.yaml @@ -326,14 +326,10 @@ resources: {} # memory: 128Mi livenessProbe: - grpc: - port: health failureThreshold: 1 periodSeconds: 10 readinessProbe: - grpc: - port: health initialDelaySeconds: 5 periodSeconds: 5 From 241b36083158725c9fedc22992ad1356d74c2b61 Mon Sep 17 00:00:00 2001 From: Ronen Hilewicz Date: Mon, 30 Sep 2024 10:16:33 -0400 Subject: [PATCH 06/19] Lint --- charts/topaz/Chart.yaml | 7 ++++++- charts/topaz/ci/test-values.yaml | 6 ++++++ charts/topaz/templates/config.yaml | 2 -- 3 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 charts/topaz/ci/test-values.yaml diff --git a/charts/topaz/Chart.yaml b/charts/topaz/Chart.yaml index 13c8517..e790948 100644 --- a/charts/topaz/Chart.yaml +++ b/charts/topaz/Chart.yaml @@ -1,6 +1,11 @@ apiVersion: v2 name: topaz description: Helm chart for the Topaz authorizer +icon: https://www.topaz.sh/img/mainLogo.svg + +maintainers: + - name: Aserto + url: https://github.com/aserto-dev # A chart can be either an 'application' or a 'library' chart. # @@ -15,7 +20,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.0 +version: 0.1.0-1 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/charts/topaz/ci/test-values.yaml b/charts/topaz/ci/test-values.yaml new file mode 100644 index 0000000..0038d95 --- /dev/null +++ b/charts/topaz/ci/test-values.yaml @@ -0,0 +1,6 @@ +opa: + policy: + oci: + registry: https://ghcr.io + # Policy image URI. + image: ghcr.io/aserto-policies/policy-rebac:latest diff --git a/charts/topaz/templates/config.yaml b/charts/topaz/templates/config.yaml index 9119f40..c2f4971 100644 --- a/charts/topaz/templates/config.yaml +++ b/charts/topaz/templates/config.yaml @@ -113,8 +113,6 @@ stringData: bearer: scheme: basic token: {{ include "topaz.ociCredentials" . }} - {{- else }} - {{- fail "either opa.policy.discovery or opa.policy.oci must be set"}} {{- end }} {{- .serviceConfig | default dict | toYaml | nindent 12 }} bundles: From cb937a5ab993142cdbd37cee6e4a6ac42b49dd11 Mon Sep 17 00:00:00 2001 From: Ronen Hilewicz Date: Mon, 30 Sep 2024 10:40:39 -0400 Subject: [PATCH 07/19] Topaz deploy notes. --- charts/topaz/templates/NOTES.txt | 40 ++++++++++++++------------------ 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/charts/topaz/templates/NOTES.txt b/charts/topaz/templates/NOTES.txt index 01cf764..5b392da 100644 --- a/charts/topaz/templates/NOTES.txt +++ b/charts/topaz/templates/NOTES.txt @@ -1,22 +1,18 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} - {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} - {{- end }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "topaz.fullname" . }}) - export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") - echo http://$NODE_IP:$NODE_PORT -{{- else if contains "LoadBalancer" .Values.service.type }} - NOTE: It may take a few minutes for the LoadBalancer IP to be available. - You can watch its status by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "topaz.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "topaz.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "topaz.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") - export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") - echo "Visit http://127.0.0.1:8080 to use your application" - kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT -{{- end }} +To access the service using the topaz CLI: +1. Forward the gRPC port to your local machine: + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "topaz.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export GRPC_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[?(@.name=='grpc')].containerPort}") + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8282:$GRPC_PORT +2. Use the topaz CLI with the `-i -H localhost:8282 --no-check` options. For example, to set a directory manifest: + topaz ds set manifest -i --no-check -H localhost:8282 manifest.yaml + + +To access the topaz web console: +1. Forward the HTTP port to your local machine: + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "topaz.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export HTTP_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[?(@.name=='http')].containerPort}") + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8383:$HTTP_PORT +2. Download the topaz self-signed certificate: + openssl s_client -showcerts -connect localhost:8383 /dev/null | openssl x509 -text > topaz-gw.crt +3. Add 'topaz-gw.crt' to your system's trusted certificates. +4. Open your browser and navigate to https://localhost:8383 From b6e034def629de8364ae4d2f23e9ca935f75d6ae Mon Sep 17 00:00:00 2001 From: Ronen Hilewicz Date: Tue, 1 Oct 2024 10:21:44 -0400 Subject: [PATCH 08/19] Add support for API keys --- charts/topaz/templates/_helpers.tpl | 39 ++++++++++++++++---------- charts/topaz/templates/config.yaml | 2 +- charts/topaz/templates/deployment.yaml | 2 +- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/charts/topaz/templates/_helpers.tpl b/charts/topaz/templates/_helpers.tpl index b578b1a..20a4ede 100644 --- a/charts/topaz/templates/_helpers.tpl +++ b/charts/topaz/templates/_helpers.tpl @@ -105,26 +105,35 @@ headers: Topaz API key configuration */}} {{- define "topaz.apiKeys" -}} +{{- $keys := list }} {{- range (.Values.auth).apiKeys }} -{{- if .key -}} -"{{ .key }}": root-key -{{- else if .secretName -}} -{{- $secretKey := .secretKey | default "api-key" }} -{{- $varName := printf "${API_KEY_%s_%s}" .secretName $secretKey | upper | replace "-" "_" }} -"{{ $varName }}": root-key -{{- end}} + {{- if .key -}} + {{- $keys = append $keys .key }} + {{- else if .secretName -}} + {{- $secretKey := .secretKey | default "api-key" }} + {{- $varName := printf "${API_KEY_%s_%s}" .secretName $secretKey | upper | replace "-" "_" }} + {{- $keys = append $keys $varName }} + {{- end}} {{- end }} +{{- $keys | toYaml }} {{- end }} -{{- define "topaz.apiKeyVolumes" -}} +{{- define "topaz.apiKeysEnv" -}} +{{- $keys := list }} {{- range (.Values.auth).apiKeys -}} -{{- if .secretName -}} -{{- $secretKey := .secretKey | default "api-key" -}} -- name: {{ printf "API_KEY_%s_%s" .secretName $secretKey | upper | replace "-" "_" }} - valueFrom: - secretKeyRef: - name: {{ .secretName }} - key: {{ $secretKey }} + {{- if .secretName -}} + {{- $keys = append $keys . }} + {{- end -}} +{{- end -}} +{{- if $keys -}} +env: +{{- range $keys }} +{{- $secretKey := .secretKey | default "api-key" }} + - name: {{ printf "API_KEY_%s_%s" .secretName $secretKey | upper | replace "-" "_" }} + valueFrom: + secretKeyRef: + name: {{ .secretName }} + key: {{ $secretKey }} {{- end }} {{- end }} {{- end }} diff --git a/charts/topaz/templates/config.yaml b/charts/topaz/templates/config.yaml index c2f4971..5f50da6 100644 --- a/charts/topaz/templates/config.yaml +++ b/charts/topaz/templates/config.yaml @@ -38,7 +38,7 @@ stringData: auth: {{- if not (empty (.Values.auth).apiKeys) }} - api_keys: + keys: {{- include "topaz.apiKeys" . | nindent 8 }} {{- end }} options: diff --git a/charts/topaz/templates/deployment.yaml b/charts/topaz/templates/deployment.yaml index 1616e2a..a4f3718 100644 --- a/charts/topaz/templates/deployment.yaml +++ b/charts/topaz/templates/deployment.yaml @@ -63,6 +63,7 @@ spec: */}} resources: {{- toYaml .Values.resources | nindent 12 }} + {{- include "topaz.apiKeysEnv" . | nindent 10 }} volumeMounts: - name: config mountPath: /config @@ -124,7 +125,6 @@ spec: {{- else }} emptyDir: {} {{- end }} - {{- include "topaz.apiKeyVolumes" . | nindent 8 }} {{- with .Values.volumes }} {{- toYaml . | nindent 8 }} {{- end }} From a2ae4a1e293398e0aa50b4b5876852986a08f60d Mon Sep 17 00:00:00 2001 From: Ronen Hilewicz Date: Tue, 1 Oct 2024 12:49:16 -0400 Subject: [PATCH 09/19] Disable directory services when using remote --- charts/topaz/templates/_helpers.tpl | 10 ++++++++-- charts/topaz/templates/config.yaml | 2 +- charts/topaz/values.yaml | 28 ++++++++++++++-------------- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/charts/topaz/templates/_helpers.tpl b/charts/topaz/templates/_helpers.tpl index 20a4ede..c5422c4 100644 --- a/charts/topaz/templates/_helpers.tpl +++ b/charts/topaz/templates/_helpers.tpl @@ -160,6 +160,9 @@ env: {{- define "topaz.svcDependencies" -}} {{- $deps := dict "reader" "model" "writer" "model" "importer" "model" "authorizer" "reader" "console" "authorizer" -}} +{{- if $.remote }} + {{- $deps = unset $deps "authorizer" }} +{{- end }} {{- $dep := get $deps .service -}} {{- if $dep -}} needs: @@ -219,8 +222,11 @@ idle_timeout: {{ $cfg.idleTimeout | default "30s" }} {{- end }} {{- define "topaz.enabledServices" -}} -{{- $services := list "authorizer" "model" "reader" | - concat (((.Values.directory).edge).services | default list) }} +{{- $services := list "authorizer" -}} +{{- if empty ((.Values.directory).remote).address -}} +{{- $services = concat $services (list "model" "reader") | + concat (((.Values.directory).edge).services | default list) }} +{{- end }} {{- if .Values.console.enabled }} {{- $services = append $services "console" }} {{- end }} diff --git a/charts/topaz/templates/config.yaml b/charts/topaz/templates/config.yaml index 5f50da6..ea0d9f7 100644 --- a/charts/topaz/templates/config.yaml +++ b/charts/topaz/templates/config.yaml @@ -74,7 +74,7 @@ stringData: services: {{- range (include "topaz.enabledServices" . | fromJsonArray) }} {{ . }}: - {{- include "topaz.svcDependencies" (dict "service" .) | nindent 10 }} + {{- include "topaz.svcDependencies" (dict "service" . "remote" (($.Values.directory).remote).address) | nindent 10 }} grpc: {{- include "topaz.grpcService" (list $.Values .) | nindent 12 }} certs: diff --git a/charts/topaz/values.yaml b/charts/topaz/values.yaml index dea6b54..1d29737 100644 --- a/charts/topaz/values.yaml +++ b/charts/topaz/values.yaml @@ -63,20 +63,20 @@ directory: # Use a remote directory instead running a local edge. # If remote is specified, edge configuration is ignored. - remote: {} - # # Remote directory address (e.g. directory.prod.aserto.com:8443) - # address: "" - # # [Optional] tenant ID for the remote directory - # tenantID: "" - # # [Optional] API key for the remote directory - # apiKey: "" - # # [Optional] Kubernetes secret containing the API key for the remote directory + remote: + # Remote directory address (e.g. directory.prod.aserto.com:8443) + address: "directory.prod.aserto.com:8443" + # [Optional] tenant ID for the remote directory + tenantID: "14cb973f-71bc-11ee-8850-007961b3967b" + # [Optional] API key for the remote directory + apiKey: "0525e7b541afa26d5ce599d9b770eb31e7ff6f08317c5411781897003b083ebe" + # [Optional] Kubernetes secret containing the API key for the remote directory # apiKeySecret: # # Secret name # name: "" # # Secret key # key: "" - # # [Optional] CA certificate for the remote directory + # [Optional] CA certificate for the remote directory # caCert: | # -----BEGIN CERTIFICATE----- # ... @@ -85,11 +85,11 @@ directory: # caCertSecret: # name: "" # key: "" - # # [Optional] Skip verification of remote TLS certificate - # skipTLSVerification: false - # # [Optional] Request timeout - # timeoutSeconds: 5 - # # [Optional] Additional headers to include in requests to the remote directory + # [Optional] Skip verification of remote TLS certificate + skipTLSVerification: false + # [Optional] Request timeout + timeoutSeconds: 5 + # [Optional] Additional headers to include in requests to the remote directory # additionalHeaders: # "header-name": header-value From cf289f0a4488548569cd95a71452c3253d41dd4e Mon Sep 17 00:00:00 2001 From: Ronen Hilewicz Date: Tue, 1 Oct 2024 15:50:12 -0400 Subject: [PATCH 10/19] health probes --- charts/topaz/templates/config.yaml | 5 ----- charts/topaz/templates/deployment.yaml | 6 ++++-- charts/topaz/values.yaml | 5 ++++- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/charts/topaz/templates/config.yaml b/charts/topaz/templates/config.yaml index ea0d9f7..a615d3a 100644 --- a/charts/topaz/templates/config.yaml +++ b/charts/topaz/templates/config.yaml @@ -57,11 +57,6 @@ stringData: api: health: listen_address: 0.0.0.0:{{ include "aserto-lib.healthPort" . }} - certs: - tls_key_path: /https-certs/tls.key - tls_cert_path: /https-certs/tls.crt - tls_ca_cert_path: /https-certs/ca.crt - {{- if (.Values.metrics).enabled }} metrics: {{- include "aserto-lib.metricsService" . | nindent 8 }} diff --git a/charts/topaz/templates/deployment.yaml b/charts/topaz/templates/deployment.yaml index a4f3718..37d931b 100644 --- a/charts/topaz/templates/deployment.yaml +++ b/charts/topaz/templates/deployment.yaml @@ -51,7 +51,10 @@ spec: containerPort: {{ (.Values.ports).metrics | default "8585" }} protocol: TCP {{- end }} - {{/* + startupProbe: + grpc: + port: {{ (.Values.ports).health | default "8484" }} + {{- toYaml .Values.startupProbe | nindent 12 }} livenessProbe: grpc: port: {{ (.Values.ports).health | default "8484" }} @@ -60,7 +63,6 @@ spec: grpc: port: {{ (.Values.ports).health | default "8484" }} {{- toYaml .Values.readinessProbe | nindent 12 }} - */}} resources: {{- toYaml .Values.resources | nindent 12 }} {{- include "topaz.apiKeysEnv" . | nindent 10 }} diff --git a/charts/topaz/values.yaml b/charts/topaz/values.yaml index 1d29737..f596ae3 100644 --- a/charts/topaz/values.yaml +++ b/charts/topaz/values.yaml @@ -330,9 +330,12 @@ livenessProbe: periodSeconds: 10 readinessProbe: - initialDelaySeconds: 5 periodSeconds: 5 +startupProbe: + failureThreshold: 30 + periodSeconds: 10 + autoscaling: enabled: false minReplicas: 1 From 8ff8f4712d789484316e2102d77d0d45ceb1b888 Mon Sep 17 00:00:00 2001 From: Ronen Hilewicz Date: Tue, 1 Oct 2024 16:23:21 -0400 Subject: [PATCH 11/19] Remote directory CA cert --- charts/topaz/templates/_helpers.tpl | 17 ++++++++++++++++- charts/topaz/templates/deployment.yaml | 1 + charts/topaz/values.yaml | 20 ++++++++++---------- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/charts/topaz/templates/_helpers.tpl b/charts/topaz/templates/_helpers.tpl index c5422c4..7466403 100644 --- a/charts/topaz/templates/_helpers.tpl +++ b/charts/topaz/templates/_helpers.tpl @@ -96,7 +96,22 @@ headers: {{- else if (.caCertSecret).name -}} - name: remote-certs secret: - secretName: {{ $name }} + secretName: {{ .caCertSecret.name }} +{{- end }} +{{- end }} +{{- end }} + +{{- define "topaz.remoteDirectoryCertVolumeMount" -}} +{{- with (.Values.directory).remote -}} +{{- if .caCert | or (.caCertSecret).name -}} +- name: remote-certs + mountPath: /directory-certs + readOnly: true +{{- end }} +{{- end }} +{{- end }} + +{{/* {{- end }} {{- end }} {{- end }} diff --git a/charts/topaz/templates/deployment.yaml b/charts/topaz/templates/deployment.yaml index 37d931b..68fc730 100644 --- a/charts/topaz/templates/deployment.yaml +++ b/charts/topaz/templates/deployment.yaml @@ -86,6 +86,7 @@ spec: {{- if (.Values.certs).https }} readOnly: true {{- end }} + {{- include "topaz.remoteDirectoryCertVolumeMount" . | nindent 12 }} {{- with .Values.volumeMounts }} {{- toYaml . | nindent 12 }} {{- end }} diff --git a/charts/topaz/values.yaml b/charts/topaz/values.yaml index f596ae3..b63487c 100644 --- a/charts/topaz/values.yaml +++ b/charts/topaz/values.yaml @@ -63,13 +63,13 @@ directory: # Use a remote directory instead running a local edge. # If remote is specified, edge configuration is ignored. - remote: - # Remote directory address (e.g. directory.prod.aserto.com:8443) - address: "directory.prod.aserto.com:8443" - # [Optional] tenant ID for the remote directory - tenantID: "14cb973f-71bc-11ee-8850-007961b3967b" - # [Optional] API key for the remote directory - apiKey: "0525e7b541afa26d5ce599d9b770eb31e7ff6f08317c5411781897003b083ebe" + remote: {} + # # Remote directory address (e.g. directory.prod.aserto.com:8443) + # address: "" + # # [Optional] tenant ID for the remote directory + # tenantID: "" + # # [Optional] API key for the remote directory + # apiKey: "" # [Optional] Kubernetes secret containing the API key for the remote directory # apiKeySecret: # # Secret name @@ -86,9 +86,9 @@ directory: # name: "" # key: "" # [Optional] Skip verification of remote TLS certificate - skipTLSVerification: false - # [Optional] Request timeout - timeoutSeconds: 5 + # skipTLSVerification: false + # # [Optional] Request timeout + # timeoutSeconds: 5 # [Optional] Additional headers to include in requests to the remote directory # additionalHeaders: # "header-name": header-value From 763075c7fba71b536d30839d19bf2358b0a6fcdd Mon Sep 17 00:00:00 2001 From: Ronen Hilewicz Date: Tue, 1 Oct 2024 17:35:00 -0400 Subject: [PATCH 12/19] Configure edge plugin --- charts/topaz/templates/_helpers.tpl | 39 ++++++++++++++++++-------- charts/topaz/templates/config.yaml | 12 ++++++++ charts/topaz/templates/deployment.yaml | 6 +++- charts/topaz/values.yaml | 34 +++++++++++----------- 4 files changed, 63 insertions(+), 28 deletions(-) diff --git a/charts/topaz/templates/_helpers.tpl b/charts/topaz/templates/_helpers.tpl index 7466403..2675c7a 100644 --- a/charts/topaz/templates/_helpers.tpl +++ b/charts/topaz/templates/_helpers.tpl @@ -67,11 +67,13 @@ Remote directory configuration {{- define "topaz.remoteDirectory" -}} {{- with (.Values.directory).remote -}} address: {{ .address }} -{{- if not (empty .tenantID) }} +{{- if .tenantID }} tenant_id: {{ .tenantID }} {{- end }} -{{- if not (empty .apiKey) }} +{{- if .apiKey }} api_key: {{ .apiKey }} +{{- else if (.apiKeySecret).name -}} +api_key: "${DIRECTORY_API_KEY}" {{- end }} {{- if .skipTLSVerification }} insecure: true @@ -134,35 +136,50 @@ Topaz API key configuration {{- end }} {{- define "topaz.apiKeysEnv" -}} -{{- $keys := list }} +{{- $keys := list -}} {{- range (.Values.auth).apiKeys -}} {{- if .secretName -}} {{- $keys = append $keys . }} {{- end -}} {{- end -}} -{{- if $keys -}} -env: -{{- range $keys }} -{{- $secretKey := .secretKey | default "api-key" }} +{{- range $keys -}} +{{- $secretKey := .secretKey | default "api-key" -}} - name: {{ printf "API_KEY_%s_%s" .secretName $secretKey | upper | replace "-" "_" }} valueFrom: secretKeyRef: name: {{ .secretName }} key: {{ $secretKey }} -{{- end }} -{{- end }} -{{- end }} +{{- end -}} +{{- end -}} {{- define "topaz.discoveryKey" -}} {{- if .apiKey -}} {{- .apiKey }} -{{- else if .apiKeySecret | and .apiKeySecret.name -}} +{{- else if (.apiKeySecret | and .apiKeySecret.name) -}} "${DISCOVERY_API_KEY}" {{- else }} {{ fail "either apiKey or apiKeySecret must be set in opa.policy.discovery" }} {{- end }} {{- end }} +{{- define "topaz.edgeKey" -}} +{{- if .apiKey -}} +{{- .apiKey -}} +{{- else if (.apiKeySecret | and .apiKeySecret.name) -}} +"${EDGE_API_KEY}" +{{- end }} +{{- end }} + +{{- define "topaz.edgeKeyEnv" -}} +{{- with (((.Values.directory).edge).sync).apiKeySecret -}} +- name: EDGE_API_KEY + valueFrom: + secretKeyRef: + name: {{ .name }} + key: {{ .key | default "api-key" }} +{{- end }} +{{- end }} + {{- define "topaz.ociCredentials" -}} {{- if (.apiKeySecret).name -}} "${REGISTRY_API_KEY}" diff --git a/charts/topaz/templates/config.yaml b/charts/topaz/templates/config.yaml index a615d3a..22440c4 100644 --- a/charts/topaz/templates/config.yaml +++ b/charts/topaz/templates/config.yaml @@ -145,3 +145,15 @@ stringData: {{- else }} {{- fail "either opa.policy.discovery or opa.policy.oci must be set"}} {{- end }} + {{- if (((.Values.directory).edge).sync).address | and (empty ((.Values.directory).remote).address) }} + plugins: + {{- with .Values.directory.edge.sync }} + aserto_edge: + addr: {{ .address }} + apikey: {{ include "topaz.edgeKey" . | default "" }} + enabled: true + insecure: {{ .skipTLSVerification | default false | toString }} + sync_interval: {{ .intervalMinutes | default "1" }} + timeout: {{ .timeoutSeconds | default "5" }} + {{- end }} + {{- end }} diff --git a/charts/topaz/templates/deployment.yaml b/charts/topaz/templates/deployment.yaml index 68fc730..234de8f 100644 --- a/charts/topaz/templates/deployment.yaml +++ b/charts/topaz/templates/deployment.yaml @@ -65,7 +65,11 @@ spec: {{- toYaml .Values.readinessProbe | nindent 12 }} resources: {{- toYaml .Values.resources | nindent 12 }} - {{- include "topaz.apiKeysEnv" . | nindent 10 }} + env: + - name: TOPAZ_CFG_DIR + value: /config + {{- include "topaz.apiKeysEnv" . | nindent 12 }} + {{- include "topaz.edgeKeyEnv" . | nindent 12 }} volumeMounts: - name: config mountPath: /config diff --git a/charts/topaz/values.yaml b/charts/topaz/values.yaml index b63487c..2f2d508 100644 --- a/charts/topaz/values.yaml +++ b/charts/topaz/values.yaml @@ -45,21 +45,23 @@ directory: # [Optional] Sync from a remote directory. sync: {} - # address: "directory.prod.aserto.com:8443" - # # [Optional] API key for the remote directory - # apiKey: "" - # # [Optional] Kubernetes secret containing the API key for the remote directory - # apiKeySecret: - # # Secret name - # name: "" - # # Secret key - # key: "" - # # Skip verification of remote TLS certificate - # skipTLSVerification: false - # # The frequency of syncs in minutes. - # intervalMinutes: 1 - # # Request timeout - # timeoutSeconds: 5 + # address: "" + # # [Optional] tenant ID for the remote directory + # tenantID: "" + # # [Optional] API key for the remote directory + # apiKey: "" + # # [Optional] Kubernetes secret containing the API key for the remote directory + # apiKeySecret: + # # Secret name + # name: "" + # # Secret key + # key: "" + # # Skip verification of remote TLS certificate + # skipTLSVerification: false + # # The frequency of syncs in minutes. + # intervalMinutes: 1 + # # Request timeout + # timeoutSeconds: 5 # Use a remote directory instead running a local edge. # If remote is specified, edge configuration is ignored. @@ -98,7 +100,7 @@ jwtAcceptableSkewSeconds: 5 auth: # [Optional] control access using API keys - # apiKeys: + apiKeys: # # keys can be specified directly # - key: a59692fa671e49a9a25861fd71472792 # # or as references to Kubernetes secrets From e2844906b17c447236e597af7d5fc98c9acc2f18 Mon Sep 17 00:00:00 2001 From: Ronen Hilewicz Date: Tue, 1 Oct 2024 19:27:16 -0400 Subject: [PATCH 13/19] Remote directory and discovery keys from secrets --- charts/topaz/templates/_helpers.tpl | 47 ++++++++++++----- charts/topaz/templates/config.yaml | 4 +- charts/topaz/templates/deployment.yaml | 2 + charts/topaz/values.yaml | 73 ++++++++++++-------------- 4 files changed, 73 insertions(+), 53 deletions(-) diff --git a/charts/topaz/templates/_helpers.tpl b/charts/topaz/templates/_helpers.tpl index 2675c7a..5f7f218 100644 --- a/charts/topaz/templates/_helpers.tpl +++ b/charts/topaz/templates/_helpers.tpl @@ -72,7 +72,7 @@ tenant_id: {{ .tenantID }} {{- end }} {{- if .apiKey }} api_key: {{ .apiKey }} -{{- else if (.apiKeySecret).name -}} +{{- else if (.apiKeySecret).name }} api_key: "${DIRECTORY_API_KEY}" {{- end }} {{- if .skipTLSVerification }} @@ -88,6 +88,16 @@ headers: {{- end }} {{- end }} +{{- define "topaz.remoteDirectoryKeyEnv" -}} +{{- with ((.Values.directory).remote).apiKeySecret -}} +- name: DIRECTORY_API_KEY + valueFrom: + secretKeyRef: + name: {{ .name }} + key: {{ .key | default "api-key" }} +{{- end }} +{{- end }} + {{- define "topaz.remoteDirectoryCertVolume" -}} {{- $name := printf "%s-remote-ca" (include "topaz.fullname" .) -}} {{- with (.Values.directory).remote -}} @@ -136,20 +146,20 @@ Topaz API key configuration {{- end }} {{- define "topaz.apiKeysEnv" -}} -{{- $keys := list -}} -{{- range (.Values.auth).apiKeys -}} +{{- $keys := list }} +{{- range (.Values.auth).apiKeys }} {{- if .secretName -}} {{- $keys = append $keys . }} - {{- end -}} -{{- end -}} -{{- range $keys -}} -{{- $secretKey := .secretKey | default "api-key" -}} - - name: {{ printf "API_KEY_%s_%s" .secretName $secretKey | upper | replace "-" "_" }} - valueFrom: - secretKeyRef: - name: {{ .secretName }} - key: {{ $secretKey }} -{{- end -}} + {{- end }} +{{- end }} +{{- range $keys }} +{{- $secretKey := .secretKey | default "api-key" }} +- name: {{ printf "API_KEY_%s_%s" .secretName $secretKey | upper | replace "-" "_" }} + valueFrom: + secretKeyRef: + name: {{ .secretName }} + key: {{ $secretKey }} +{{- end }} {{- end -}} {{- define "topaz.discoveryKey" -}} @@ -162,6 +172,17 @@ Topaz API key configuration {{- end }} {{- end }} +{{- define "topaz.discoveryKeyEnv" -}} +{{- with (((.Values.opa).policy).discovery).apiKeySecret -}} +- name: DISCOVERY_API_KEY + valueFrom: + secretKeyRef: + name: {{ .name }} + key: {{ .key | default "api-key" }} +{{- end }} +{{- end }} + + {{- define "topaz.edgeKey" -}} {{- if .apiKey -}} {{- .apiKey -}} diff --git a/charts/topaz/templates/config.yaml b/charts/topaz/templates/config.yaml index 22440c4..afc76ff 100644 --- a/charts/topaz/templates/config.yaml +++ b/charts/topaz/templates/config.yaml @@ -85,7 +85,7 @@ stringData: {{- end }} opa: - instance_id: {{ .Values.tenantID | default (quote "-") }} + instance_id: {{ ((.Values.policy).discovery).tenantID | default (quote "-") }} graceful_shutdown_period_seconds: {{ (.Values.opa).gracefuShutdownPeriodSeconds | default "2" }} max_plugin_wait_time_seconds: {{ (.Values.opa).maxPluginWaitTimeSeconds | default "30" }} local_bundles: @@ -132,7 +132,7 @@ stringData: {{- $headers := dig "headers" dict $cfg -}} {{ $cfg = unset $cfg "headers" }} headers: - Aserto-Tenant-Id: {{ $.Values.tenantID | required "policy discovery requires tenantID to be set" }} + Aserto-Tenant-Id: {{ .tenantID | required "policy discovery requires tenantID to be set" }} {{- if $headers }} {{- $headers | toYaml | nindent 14 }} {{- end }} diff --git a/charts/topaz/templates/deployment.yaml b/charts/topaz/templates/deployment.yaml index 234de8f..3fb309f 100644 --- a/charts/topaz/templates/deployment.yaml +++ b/charts/topaz/templates/deployment.yaml @@ -68,8 +68,10 @@ spec: env: - name: TOPAZ_CFG_DIR value: /config + {{- include "topaz.remoteDirectoryKeyEnv" . | nindent 12 }} {{- include "topaz.apiKeysEnv" . | nindent 12 }} {{- include "topaz.edgeKeyEnv" . | nindent 12 }} + {{- include "topaz.discoveryKeyEnv" . | nindent 12 }} volumeMounts: - name: config mountPath: /config diff --git a/charts/topaz/values.yaml b/charts/topaz/values.yaml index 2f2d508..1bc6046 100644 --- a/charts/topaz/values.yaml +++ b/charts/topaz/values.yaml @@ -55,7 +55,7 @@ directory: # # Secret name # name: "" # # Secret key - # key: "" + # key: "api-key" # # Skip verification of remote TLS certificate # skipTLSVerification: false # # The frequency of syncs in minutes. @@ -86,7 +86,7 @@ directory: # # [Optional] Kubernetes secret containing the CA certificate for the remote directory # caCertSecret: # name: "" - # key: "" + # key: "api-key" # [Optional] Skip verification of remote TLS certificate # skipTLSVerification: false # # [Optional] Request timeout @@ -206,36 +206,36 @@ opa: # Exactly one of them must be specified. # Run policy from an OCI registry. - oci: - # OCI registry URL. - registry: https://ghcr.io - # Policy image URI. - image: "ghcr.io/aserto-policies/policy-rebac:latest" - # [Optional] OCI registry user name. - # Note: Some registries including ghcr.io require that the user name is left empty - # when using a personal access token as the API key. - user: "" - # [Optional] OCI registry password, token, or API key. - apiKey: "" - # [Optional] Kubernetes secret containing the OCI registry password, token, or API key. - apiKeySecret: - # Secret name - name: "" - # Secret key - key: "" - # Additional OPA service configuration. - # See https://www.openpolicyagent.org/docs/latest/configuration/#services - serviceConfig: - response_header_timeout_seconds: 5 - # allow_insecure_tls: false - # headers: - # "header-name": header-value - # Additional OPA bundle configuration. - # See https://www.openpolicyagent.org/docs/latest/configuration/#bundles - bundleConfig: - polling: - min_delay_seconds: 60 - max_delay_seconds: 120 + oci: {} + # # OCI registry URL. + # registry: https://ghcr.io + # # Policy image URI. + # image: "ghcr.io/aserto-policies/policy-rebac:latest" + # # [Optional] OCI registry user name. + # # Note: Some registries including ghcr.io require that the user name is left empty + # # when using a personal access token as the API key. + # user: "" + # # [Optional] OCI registry password, token, or API key. + # apiKey: "" + # # [Optional] Kubernetes secret containing the OCI registry password, token, or API key. + # apiKeySecret: + # # Secret name + # name: "" + # # Secret key + # key: "api-key" + # # Additional OPA service configuration. + # # See https://www.openpolicyagent.org/docs/latest/configuration/#services + # serviceConfig: + # response_header_timeout_seconds: 5 + # # allow_insecure_tls: false + # # headers: + # # "header-name": header-value + # # Additional OPA bundle configuration. + # # See https://www.openpolicyagent.org/docs/latest/configuration/#bundles + # bundleConfig: + # polling: + # min_delay_seconds: 60 + # max_delay_seconds: 120 # Retrieve policy configuration from a discovery service. discovery: {} @@ -243,6 +243,8 @@ opa: # url: https://discovery.prod.aserto.com/api/v2/discovery # # Name of policy to run. # policyName: "policy-name" + # # ID of the tenant that owns the policy. + # tenantID: "" # # [Optional] Discovery service API key. # apiKey: "" # # [Optional] Kubernetes secret containing the discovery service API key. @@ -250,7 +252,7 @@ opa: # # Secret name # name: "" # # Secret key - # key: "" + # key: "api-key" # serviceConfig: # # Additional OPA service configuration. # # See https://www.openpolicyagent.org/docs/latest/configuration/#services @@ -259,11 +261,6 @@ opa: # # headers: # # "header-name": header-value -# [Optional] ID of the tenant that owns the policy. -# This is required when running a policy from a discovery service. -tenantID: "" - - # Standard Kubernetes configuration replicaCount: 1 From c6a9ebf090f27028dd609c7e9fa8e488442dbd27 Mon Sep 17 00:00:00 2001 From: Ronen Hilewicz Date: Tue, 8 Oct 2024 18:15:12 -0400 Subject: [PATCH 14/19] Decision logging configuration --- charts/topaz/templates/_helpers.tpl | 59 +++++++++++++++++- charts/topaz/templates/config.yaml | 12 +++- charts/topaz/templates/deployment.yaml | 33 +++++++--- charts/topaz/templates/pvc-db.yaml | 2 +- charts/topaz/templates/pvc-decisions.yaml | 22 +++++++ charts/topaz/templates/pvc-policy.yaml | 4 +- .../topaz/templates/secret-scribe-cert.yaml | 15 +++++ charts/topaz/values.yaml | 61 ++++++++++++++++++- 8 files changed, 193 insertions(+), 15 deletions(-) create mode 100644 charts/topaz/templates/pvc-decisions.yaml create mode 100644 charts/topaz/templates/secret-scribe-cert.yaml diff --git a/charts/topaz/templates/_helpers.tpl b/charts/topaz/templates/_helpers.tpl index 5f7f218..4a59f14 100644 --- a/charts/topaz/templates/_helpers.tpl +++ b/charts/topaz/templates/_helpers.tpl @@ -114,14 +114,12 @@ headers: {{- end }} {{- define "topaz.remoteDirectoryCertVolumeMount" -}} -{{- with (.Values.directory).remote -}} {{- if .caCert | or (.caCertSecret).name -}} - name: remote-certs mountPath: /directory-certs readOnly: true {{- end }} {{- end }} -{{- end }} {{/* {{- end }} @@ -285,3 +283,60 @@ idle_timeout: {{ $cfg.idleTimeout | default "30s" }} {{- end }} {{- $services | toJson }} {{- end }} + +{{- define "topaz.decisionLogger" -}} +{{- with .Values.decisionLogs -}} +{{- if .file -}} +type: file +config: + log_file_path: /decisions/decisions.log + max_file_size_mb: {{ .file.maxFileSizeMB | default "50" }} + max_file_count: {{ .file.maxFileCount | default "2" }} +{{- else if .remote -}} +type: self +config: + store_directory: "/decisions" + port: {{ .remote.natsPort | default "4222" }} + shipper: + {{- with .remote.shipper | default dict }} + max_bytes: {{ .maxSpoolSizeMB | default 100 | mul 1024 | mul 1024 }} + max_batch_size: {{ .maxBatchSize | default "512" }} + publish_timeout_seconds: {{ .publishTimeoutSec | default "10"}} + max_inflight_batches: {{ .maxInflightBatches | default "10" }} + delete_stream_on_done: {{ .deleteStreamOnDone | default "false" }} + {{- end }} + scribe: + {{- with .remote.scribe | default dict }} + address: {{ .address | default "ems.prod.aserto.com:8443" }} + {{- if not (.mtlsCert | or .mtlsKey | or .mtlsCertSecretName) }} + {{ fail "decisionLogs.remote.scribe must contain either mtlsCertSecretName or mtlsCert and mtlsKey" }} + {{- end }} + client_cert_path: /scribe-cert/tls.crt + client_key_path: /scribe-cert/tls.key + ack_wait_seconds: {{ .ackWaitSec | default "60" }} + {{- if .skipTLSVerification }} + insecure: true + {{- end }} + headers: + Aserto-Tenant-Id: {{ .tenantID | required "decisionLogs.remote.scribe.tenantID is required" }} + {{- end }} +{{- else -}} +{{- fail "either decisionLogs.file or decisionLogs.remote must be set" }} +{{- end }} +{{- end }} +{{- end }} + + +{{- define "topaz.scribeCertVolume" -}} +{{- with ((.Values.decisionLogs).remote).scribe | required "missing required decisionLogs.remote.scribe configuration" -}} +- name: scribe-cert + secret: + {{- if .mtlsCert | and .mtlsKey }} + secretName: {{ include "topaz.fullname" $ }}-scribe-client-cert + {{- else if .mtlsCertSecretName }} + secretName: {{ .mtlsCertSecretName }} + {{- else }} + {{- fail "decisionLogs.remote.scribe must contain either mtlsCertSecretName or mtlsCert and mtlsKey" }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/topaz/templates/config.yaml b/charts/topaz/templates/config.yaml index afc76ff..571e226 100644 --- a/charts/topaz/templates/config.yaml +++ b/charts/topaz/templates/config.yaml @@ -84,8 +84,16 @@ stringData: tls_ca_cert_path: /https-certs/ca.crt {{- end }} + {{- if (.Values.decisionLogs).enabled -}} + {{- if (.Values.decisionLogs).file | and (.Values.decisionLogs).remote -}} + {{- fail "decisionLogs.file and decisionLogs.remote are mutually exclusive" }} + {{- end }} + decision_logger: + {{- include "topaz.decisionLogger" . | nindent 6 }} + {{ end -}} + opa: - instance_id: {{ ((.Values.policy).discovery).tenantID | default (quote "-") }} + instance_id: {{ (((.Values.opa).policy).discovery).tenantID | default (quote "-") }} graceful_shutdown_period_seconds: {{ (.Values.opa).gracefuShutdownPeriodSeconds | default "2" }} max_plugin_wait_time_seconds: {{ (.Values.opa).maxPluginWaitTimeSeconds | default "30" }} local_bundles: @@ -109,7 +117,7 @@ stringData: scheme: basic token: {{ include "topaz.ociCredentials" . }} {{- end }} - {{- .serviceConfig | default dict | toYaml | nindent 12 }} + {{- .serviceConfig | default (dict "response_header_timeout_seconds" 5) | toYaml | nindent 12 }} bundles: topaz_policy: service: oci diff --git a/charts/topaz/templates/deployment.yaml b/charts/topaz/templates/deployment.yaml index 3fb309f..763123d 100644 --- a/charts/topaz/templates/deployment.yaml +++ b/charts/topaz/templates/deployment.yaml @@ -68,10 +68,10 @@ spec: env: - name: TOPAZ_CFG_DIR value: /config - {{- include "topaz.remoteDirectoryKeyEnv" . | nindent 12 }} - {{- include "topaz.apiKeysEnv" . | nindent 12 }} - {{- include "topaz.edgeKeyEnv" . | nindent 12 }} - {{- include "topaz.discoveryKeyEnv" . | nindent 12 }} + {{ include "topaz.remoteDirectoryKeyEnv" . | nindent 12 }} + {{ include "topaz.apiKeysEnv" . | nindent 12 }} + {{ include "topaz.edgeKeyEnv" . | nindent 12 }} + {{ include "topaz.discoveryKeyEnv" . | nindent 12 }} volumeMounts: - name: config mountPath: /config @@ -79,6 +79,9 @@ spec: - name: db mountPath: /db readOnly: false + - name: decisions + mountPath: /decisions + readOnly: false - name: opa mountPath: /opa-persistence readOnly: false @@ -92,7 +95,13 @@ spec: {{- if (.Values.certs).https }} readOnly: true {{- end }} - {{- include "topaz.remoteDirectoryCertVolumeMount" . | nindent 12 }} + {{- with (.Values.directory).remote -}} + {{ include "topaz.remoteDirectoryCertVolumeMount" . | nindent 12 }} + {{- end -}} + {{- if (.Values.decisionLogs).remote }} + - name: scribe-cert + mountPath: /scribe-cert + {{- end }} {{- with .Values.volumeMounts }} {{- toYaml . | nindent 12 }} {{- end }} @@ -123,17 +132,27 @@ spec: - name: db {{- if empty (.Values.directory).remote | and (((.Values.directory).edge).persistence).enabled }} persistentVolumeClaim: - claimName: pvc-db + claimName: {{ include "topaz.fullname" . }}-pvc-db {{- else }} emptyDir: {} {{- end }} - name: opa {{- if ((.Values.opa).persistence).enabled }} persistentVolumeClaim: - claimName: pvc-policy + claimName: {{ include "topaz.fullname" . }}-pvc-policy + {{- else }} + emptyDir: {} + {{- end }} + - name: decisions + {{- if (.Values.decisionLogs).enabled | and ((.Values.decisionLogs).persistence).enabled }} + persistentVolumeClaim: + claimName: {{ include "topaz.fullname" . }}-pvc-decisions {{- else }} emptyDir: {} {{- end }} + {{- if (.Values.decisionLogs).remote -}} + {{- include "topaz.scribeCertVolume" . | nindent 8 }} + {{- end -}} {{- with .Values.volumes }} {{- toYaml . | nindent 8 }} {{- end }} diff --git a/charts/topaz/templates/pvc-db.yaml b/charts/topaz/templates/pvc-db.yaml index e815b3e..f08e1be 100644 --- a/charts/topaz/templates/pvc-db.yaml +++ b/charts/topaz/templates/pvc-db.yaml @@ -3,7 +3,7 @@ apiVersion: v1 kind: PersistentVolumeClaim metadata: - name: pvc-db + name: {{ include "topaz.fullname" $ }}-pvc-db spec: accessModes: - ReadWriteOnce diff --git a/charts/topaz/templates/pvc-decisions.yaml b/charts/topaz/templates/pvc-decisions.yaml new file mode 100644 index 0000000..ace6b48 --- /dev/null +++ b/charts/topaz/templates/pvc-decisions.yaml @@ -0,0 +1,22 @@ +{{- with (.Values.decisionLogs).persistence -}} +{{- if .enabled | and ($.Values.decisionLogs).enabled }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ include "topaz.fullname" $ }}-pvc-decisions +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .storage | default "100Mi" }} + {{- if .storageClassName }} + storageClassName: {{ .storageClassName }} + {{- end }} + {{- if .selector }} + selector: + {{- .selector | toYaml | nindent 4 }} + {{- end }} +{{- end }} +{{- end }} + diff --git a/charts/topaz/templates/pvc-policy.yaml b/charts/topaz/templates/pvc-policy.yaml index 54d6de9..d73e7b2 100644 --- a/charts/topaz/templates/pvc-policy.yaml +++ b/charts/topaz/templates/pvc-policy.yaml @@ -1,9 +1,9 @@ -{{- if ((.Values.opa).persistence).enabled }} {{- with (.Values.opa).persistence }} +{{- if .enabled }} apiVersion: v1 kind: PersistentVolumeClaim metadata: - name: pvc-policy + name: {{ include "topaz.fullname" $ }}-pvc-policy spec: accessModes: - ReadWriteOnce diff --git a/charts/topaz/templates/secret-scribe-cert.yaml b/charts/topaz/templates/secret-scribe-cert.yaml new file mode 100644 index 0000000..41330c8 --- /dev/null +++ b/charts/topaz/templates/secret-scribe-cert.yaml @@ -0,0 +1,15 @@ +{{- with ((.Values.decisionLogs).remote).scribe }} +{{- if .mtlsCert }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "topaz.fullname" $ }}-scribe-client-cert +type: kubernetes.io/tls +stringData: + tls.crt: | + {{- .mtlsCert | nindent 4 }} + tls.key: | + {{- .mtlsKey | nindent 4 }} +{{- end }} +{{- end }} diff --git a/charts/topaz/values.yaml b/charts/topaz/values.yaml index 1bc6046..c29c681 100644 --- a/charts/topaz/values.yaml +++ b/charts/topaz/values.yaml @@ -95,6 +95,65 @@ directory: # additionalHeaders: # "header-name": header-value +decisionLogs: + enabled: true + # The 'file' and 'remote' options are mutually exclusive. + file: {} + # # Write decision logs to a local file. + # # The logs are written to the spool directory (/decisions) and rotated when they reach the maximum size. + # maxFileSizeMB: 50 + # maxFileCount: 2 + remote: {} + # # Send decision logs to a remote scribe. + # natsPort: 4222 + # shipper: + # # [Optional] Maximum size of the local spool directory in MB. + # maxSpoolSizeMB: 100 + # # [Optional] Maximum number of decisions in a batch. + # maxBatchSize: 512 + # # [Optional] Maximum time to wait for a batch to fill up. + # # If the batch is not full, it will be sent after this time. + # publishTimeoutSec: 10 + # # [Optional] Maximum number of batches to send concurrently. + # maxInFlightBatches: 10 + # # [Optional] If true, clear the spool directory on shutdown. + # deleteOnShutdown: false + # scribe: + # # [Optional] Scribe server address. + # address: ems.prod.aserto.com:8443 + # # [Required] ID of the tenant that owns the policy. + # tenantID: "" + # # mTLS configuration. Either mtlsCertSecretName or mtlsCert and mtlsKey must be provided. + # # [Optional] mTLS client certificate. + # mtlsCert: | + # -----BEGIN CERTIFICATE----- + # ... + # -----END CERTIFICATE----- + # # [Optional] mTLS client private key. + # mtlsKey: | + # -----BEGIN RSA PRIVATE KEY----- + # ... + # -----END RSA PRIVATE KEY----- + # # [Optional] Kubernetes secret containing the mTLS client certificate and private key. + # # Must be a secret of type kubernetes.io/tls. + # mtlsCertSecretName: "" + # # Skip verification of remote TLS certificate + # skipTLSVerification: false + # # headers: + # # "header-name": header-value + # # [Optional] Duration to wait for a batch of decisions to be acknowledged by the server. + # # If the server does not acknowledge the batch within this time, the batch is resent. + # ackWaitSec: 60 + persistence: + enabled: false + # PersistentVolumeClaim options. + # See https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims + # storage: 100Mi + # storageClassName: "" + # selector: + # matchLabels: + # release: "stable" + # Acceptable clock skew for JWT validation. jwtAcceptableSkewSeconds: 5 @@ -207,7 +266,7 @@ opa: # Run policy from an OCI registry. oci: {} - # # OCI registry URL. + # # oci registry url. # registry: https://ghcr.io # # Policy image URI. # image: "ghcr.io/aserto-policies/policy-rebac:latest" From e5d2ffa06596e927476d6206e5f14c53c46e007c Mon Sep 17 00:00:00 2001 From: Ronen Hilewicz Date: Tue, 8 Oct 2024 21:00:49 -0400 Subject: [PATCH 15/19] Controller configuration --- charts/topaz/templates/_helpers.tpl | 72 ++++++++++++++++--- charts/topaz/templates/config.yaml | 22 +++--- charts/topaz/templates/deployment.yaml | 23 +++--- .../templates/secret-controller-cert.yaml | 18 +++++ charts/topaz/values.yaml | 32 +++++++-- 5 files changed, 137 insertions(+), 30 deletions(-) create mode 100644 charts/topaz/templates/secret-controller-cert.yaml diff --git a/charts/topaz/templates/_helpers.tpl b/charts/topaz/templates/_helpers.tpl index 4a59f14..0efe2a6 100644 --- a/charts/topaz/templates/_helpers.tpl +++ b/charts/topaz/templates/_helpers.tpl @@ -61,6 +61,17 @@ Create the name of the service account to use {{- end }} {{- end }} + +{{- define "topaz.appKind" -}} +{{- if (((.Values.directory).edge).persistence).enabled | + or ((.Values.decisionLogs).persistence).enabled | + or ((.Values.opa).persistence).enabled -}} +StatefulSet +{{- else -}} +Deployment +{{- end }} +{{- end }} + {{/* Remote directory configuration */}} @@ -81,13 +92,14 @@ insecure: true {{- if not (empty .caCert | and (empty .caCertSecret)) }} ca_cert_path: /directory-certs/{{ (.caCertSecret).key | default "tls.crt" }} {{- end }} -{{- if not (empty .additionalHeaders) }} +{{- with .additionalHeaders }} headers: - {{- toYaml .additionalHeaders | toYaml | nindent 2 }} + {{- toYaml . | toYaml | nindent 2 }} {{- end }} {{- end }} {{- end }} + {{- define "topaz.remoteDirectoryKeyEnv" -}} {{- with ((.Values.directory).remote).apiKeySecret -}} - name: DIRECTORY_API_KEY @@ -98,6 +110,7 @@ headers: {{- end }} {{- end }} + {{- define "topaz.remoteDirectoryCertVolume" -}} {{- $name := printf "%s-remote-ca" (include "topaz.fullname" .) -}} {{- with (.Values.directory).remote -}} @@ -113,6 +126,7 @@ headers: {{- end }} {{- end }} + {{- define "topaz.remoteDirectoryCertVolumeMount" -}} {{- if .caCert | or (.caCertSecret).name -}} - name: remote-certs @@ -121,11 +135,6 @@ headers: {{- end }} {{- end }} -{{/* -{{- end }} -{{- end }} -{{- end }} - {{/* Topaz API key configuration */}} @@ -143,6 +152,7 @@ Topaz API key configuration {{- $keys | toYaml }} {{- end }} + {{- define "topaz.apiKeysEnv" -}} {{- $keys := list }} {{- range (.Values.auth).apiKeys }} @@ -160,6 +170,7 @@ Topaz API key configuration {{- end }} {{- end -}} + {{- define "topaz.discoveryKey" -}} {{- if .apiKey -}} {{- .apiKey }} @@ -170,6 +181,7 @@ Topaz API key configuration {{- end }} {{- end }} + {{- define "topaz.discoveryKeyEnv" -}} {{- with (((.Values.opa).policy).discovery).apiKeySecret -}} - name: DISCOVERY_API_KEY @@ -199,6 +211,7 @@ Topaz API key configuration {{- end }} {{- end }} + {{- define "topaz.ociCredentials" -}} {{- if (.apiKeySecret).name -}} "${REGISTRY_API_KEY}" @@ -209,6 +222,7 @@ Topaz API key configuration {{- end }} {{- end }} + {{- define "topaz.svcDependencies" -}} {{- $deps := dict "reader" "model" "writer" "model" "importer" "model" "authorizer" "reader" "console" "authorizer" -}} {{- if $.remote }} @@ -221,6 +235,7 @@ needs: {{- end }} {{- end }} + {{- define "topaz.grpcService" -}} {{- $values := first . -}} {{- $svc := last . -}} @@ -268,10 +283,12 @@ write_timeout: {{ $cfg.writeTimeout | default "2s" }} idle_timeout: {{ $cfg.idleTimeout | default "30s" }} {{- end }} + {{- define "topaz.discoveryResource" -}} {{- printf "%s/%s/opa" .policyName .policyName }} {{- end }} + {{- define "topaz.enabledServices" -}} {{- $services := list "authorizer" -}} {{- if empty ((.Values.directory).remote).address -}} @@ -284,6 +301,7 @@ idle_timeout: {{ $cfg.idleTimeout | default "30s" }} {{- $services | toJson }} {{- end }} + {{- define "topaz.decisionLogger" -}} {{- with .Values.decisionLogs -}} {{- if .file -}} @@ -306,8 +324,9 @@ config: delete_stream_on_done: {{ .deleteStreamOnDone | default "false" }} {{- end }} scribe: - {{- with .remote.scribe | default dict }} + {{- with .remote.scribe | default dict }} address: {{ .address | default "ems.prod.aserto.com:8443" }} + tenant_id: {{ .tenantID | required "decisionLogs.remote.scribe.tenantID is required" }} {{- if not (.mtlsCert | or .mtlsKey | or .mtlsCertSecretName) }} {{ fail "decisionLogs.remote.scribe must contain either mtlsCertSecretName or mtlsCert and mtlsKey" }} {{- end }} @@ -317,9 +336,11 @@ config: {{- if .skipTLSVerification }} insecure: true {{- end }} + {{- with .additionalHeaders }} headers: - Aserto-Tenant-Id: {{ .tenantID | required "decisionLogs.remote.scribe.tenantID is required" }} + {{- toYaml . | toYaml | nindent 6 }} {{- end }} + {{- end }} {{- else -}} {{- fail "either decisionLogs.file or decisionLogs.remote must be set" }} {{- end }} @@ -340,3 +361,36 @@ config: {{- end }} {{- end }} {{- end }} + + +{{- define "topaz.controller" -}} +enabled: true +server: + {{- with .Values.controller }} + address: {{ .address | default "relay.prod.aserto.com:8443" }} + client_cert_path: /controller-cert/tls.crt + client_key_path: /controller-cert/tls.key + {{- if .skipTLSVerification }} + insecure: true + {{- end }} + {{- with .additionalHeaders }} + headers: + {{- toYaml . | toYaml | nindent 4 }} + {{- end }} + {{- end }} +{{- end }} + + +{{- define "topaz.controllerCertVolume" -}} +{{- with .Values.controller -}} +- name: controller-cert + secret: + {{- if .mtlsCert | and .mtlsKey }} + secretName: {{ include "topaz.fullname" $ }}-controller-client-cert + {{- else if .mtlsCertSecretName }} + secretName: {{ .mtlsCertSecretName }} + {{- else }} + {{- fail "controller must contain either mtlsCertSecretName or mtlsCert and mtlsKey" }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/topaz/templates/config.yaml b/charts/topaz/templates/config.yaml index 571e226..f19dede 100644 --- a/charts/topaz/templates/config.yaml +++ b/charts/topaz/templates/config.yaml @@ -57,17 +57,17 @@ stringData: api: health: listen_address: 0.0.0.0:{{ include "aserto-lib.healthPort" . }} - {{- if (.Values.metrics).enabled }} + {{- if (.Values.metrics).enabled }} metrics: {{- include "aserto-lib.metricsService" . | nindent 8 }} certs: tls_key_path: /https-certs/tls.key tls_cert_path: /https-certs/tls.crt tls_ca_cert_path: /https-certs/ca.crt - {{- end }} + {{- end }} services: - {{- range (include "topaz.enabledServices" . | fromJsonArray) }} + {{- range (include "topaz.enabledServices" . | fromJsonArray) }} {{ . }}: {{- include "topaz.svcDependencies" (dict "service" . "remote" (($.Values.directory).remote).address) | nindent 10 }} grpc: @@ -82,16 +82,20 @@ stringData: tls_key_path: /https-certs/tls.key tls_cert_path: /https-certs/tls.crt tls_ca_cert_path: /https-certs/ca.crt - {{- end }} - - {{- if (.Values.decisionLogs).enabled -}} - {{- if (.Values.decisionLogs).file | and (.Values.decisionLogs).remote -}} - {{- fail "decisionLogs.file and decisionLogs.remote are mutually exclusive" }} {{- end }} + + {{- if (.Values.decisionLogs).enabled -}} + {{- if (.Values.decisionLogs).file | and (.Values.decisionLogs).remote -}} + {{- fail "decisionLogs.file and decisionLogs.remote are mutually exclusive" }} + {{- end }} decision_logger: {{- include "topaz.decisionLogger" . | nindent 6 }} - {{ end -}} + {{ end }} + {{ if (.Values.controller).enabled -}} + controller: + {{- include "topaz.controller" . | nindent 6 }} + {{- end }} opa: instance_id: {{ (((.Values.opa).policy).discovery).tenantID | default (quote "-") }} graceful_shutdown_period_seconds: {{ (.Values.opa).gracefuShutdownPeriodSeconds | default "2" }} diff --git a/charts/topaz/templates/deployment.yaml b/charts/topaz/templates/deployment.yaml index 763123d..0ff9fd6 100644 --- a/charts/topaz/templates/deployment.yaml +++ b/charts/topaz/templates/deployment.yaml @@ -1,5 +1,5 @@ apiVersion: apps/v1 -kind: StatefulSet +kind: {{ include "topaz.appKind" . }} metadata: name: {{ include "topaz.fullname" . }} labels: @@ -65,13 +65,6 @@ spec: {{- toYaml .Values.readinessProbe | nindent 12 }} resources: {{- toYaml .Values.resources | nindent 12 }} - env: - - name: TOPAZ_CFG_DIR - value: /config - {{ include "topaz.remoteDirectoryKeyEnv" . | nindent 12 }} - {{ include "topaz.apiKeysEnv" . | nindent 12 }} - {{ include "topaz.edgeKeyEnv" . | nindent 12 }} - {{ include "topaz.discoveryKeyEnv" . | nindent 12 }} volumeMounts: - name: config mountPath: /config @@ -101,10 +94,21 @@ spec: {{- if (.Values.decisionLogs).remote }} - name: scribe-cert mountPath: /scribe-cert + {{- end }} + {{- if (.Values.controller).enabled }} + - name: controller-cert + mountPath: /controller-cert {{- end }} {{- with .Values.volumeMounts }} {{- toYaml . | nindent 12 }} {{- end }} + env: + - name: TOPAZ_CFG_DIR + value: /config + {{ include "topaz.remoteDirectoryKeyEnv" . | nindent 12 }} + {{ include "topaz.apiKeysEnv" . | nindent 12 }} + {{ include "topaz.edgeKeyEnv" . | nindent 12 }} + {{ include "topaz.discoveryKeyEnv" . | nindent 12 }} volumes: - name: config secret: @@ -153,6 +157,9 @@ spec: {{- if (.Values.decisionLogs).remote -}} {{- include "topaz.scribeCertVolume" . | nindent 8 }} {{- end -}} + {{- if (.Values.controller).enabled -}} + {{- include "topaz.controllerCertVolume" .| nindent 8 }} + {{- end -}} {{- with .Values.volumes }} {{- toYaml . | nindent 8 }} {{- end }} diff --git a/charts/topaz/templates/secret-controller-cert.yaml b/charts/topaz/templates/secret-controller-cert.yaml new file mode 100644 index 0000000..8ef7824 --- /dev/null +++ b/charts/topaz/templates/secret-controller-cert.yaml @@ -0,0 +1,18 @@ +{{- with .Values.controller }} +{{- if .enabled | and .mtlsCert }} +{{- if empty .mtlsKey }} + {{- fail "controller requires either mtlsCertSecretName or mtlsCert and mtlsKey" }} +{{- end }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "topaz.fullname" $ }}-controller-client-cert +type: kubernetes.io/tls +stringData: + tls.crt: | + {{- .mtlsCert | nindent 4 }} + tls.key: | + {{- .mtlsKey | nindent 4 }} +{{- end }} +{{- end }} diff --git a/charts/topaz/values.yaml b/charts/topaz/values.yaml index c29c681..3e7afb7 100644 --- a/charts/topaz/values.yaml +++ b/charts/topaz/values.yaml @@ -95,8 +95,32 @@ directory: # additionalHeaders: # "header-name": header-value +controller: + enabled: false + # # [Optional] Controller server address. + # address: relay.prod.aserto.com:8443 + # # mTLS configuration. Either mtlsCertSecretName or mtlsCert and mtlsKey must be provided. + # # [Optional] mTLS client certificate. + # mtlsCert: | + # -----BEGIN CERTIFICATE----- + # ... + # -----END CERTIFICATE----- + # # [Optional] mTLS client private key. + # mtlsKey: | + # -----BEGIN RSA PRIVATE KEY----- + # ... + # -----END RSA PRIVATE KEY----- + # # [Optional] Kubernetes secret containing the mTLS client certificate and private key. + # # Must be a secret of type kubernetes.io/tls. + # mtlsCertSecretName: "" + # # Skip verification of server certificate + # skipTLSVerification: false + # # [Optional] Additional headers to include in requests to the controller. + # additionalHeaders: + # "header-name": header-value + decisionLogs: - enabled: true + enabled: false # The 'file' and 'remote' options are mutually exclusive. file: {} # # Write decision logs to a local file. @@ -137,15 +161,15 @@ decisionLogs: # # [Optional] Kubernetes secret containing the mTLS client certificate and private key. # # Must be a secret of type kubernetes.io/tls. # mtlsCertSecretName: "" - # # Skip verification of remote TLS certificate + # # Skip verification of server certificate # skipTLSVerification: false - # # headers: + # # additionslHeaders: # # "header-name": header-value # # [Optional] Duration to wait for a batch of decisions to be acknowledged by the server. # # If the server does not acknowledge the batch within this time, the batch is resent. # ackWaitSec: 60 persistence: - enabled: false + enabled: true # PersistentVolumeClaim options. # See https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims # storage: 100Mi From fb3fb8267dc3138435c87e6973c35ff4a74584f3 Mon Sep 17 00:00:00 2001 From: Ronen Hilewicz Date: Wed, 9 Oct 2024 17:53:29 -0400 Subject: [PATCH 16/19] Topaz README.md --- charts/topaz/README.md | 374 ++++++++++++++++++++++++++++ charts/topaz/templates/_helpers.tpl | 14 +- charts/topaz/values.yaml | 10 +- 3 files changed, 386 insertions(+), 12 deletions(-) create mode 100644 charts/topaz/README.md diff --git a/charts/topaz/README.md b/charts/topaz/README.md new file mode 100644 index 0000000..140a480 --- /dev/null +++ b/charts/topaz/README.md @@ -0,0 +1,374 @@ +# Topaz Helm Chart + +[Topaz](https://www.topaz.sh) is an open source authorization service providing fine grained, real-time, +policy based access control for applications and APIs. + +The topaz chart is used to deploy instances of the topaz authorizer to a Kubernetes cluster. +A topaz instance can run standalone or connect to a control plane hosted by Aserto or self-hosted +in your own cluster. +Use the [aserto chart](https://github.com/aserto-dev/helm/blob/main/README.md) to deploy a self-hosted +control plane. + + +## Requirements + +### Helm + +[Helm](https://helm.sh) must be installed to use the charts. +Please refer to Helm's [documentation](https://helm.sh/docs/intro/install) to get started. + +Full OCI support is available starting from Helm v3.8.0. If you are using an older version, +follow Helm's [instructions](https://helm.sh/docs/topics/registries/) on how to enable OCI +registries. + + +## Configuration + +The default [values.yaml](https://github.com/aserto-dev/helm/blob/main/charts/topaz/values.yaml) +is a good starting point for configuring topaz. +The only required configuration element that does not have a default value is `opa.poilcy` that +must either specify a policy image to load from an OCI registry, or point to a discovery service +for dynamic configuration. + +The following sections describe the various configuration options available in the chart. + + +## OPA Policy + +Topaz is built on top of the [Open Policy Agent](https://www.openpolicyagent.org) (OPA) and uses +it to evaluate authorization poicies. The `opa` section of `values.yaml` is used to configure OPA. +There are two ways to specify the poilcy to use: +1. By configuring topaz with a policy image stored in an OCI registry. +2. By pointing topaz to a discovery service that provides it with the necessary configuration options. + When using discovery, topaz periodically polls the service for updates to the policy and/or OPA + plugins. + +> [!IMPORTANT] +> Explicitly specifying a policy image and using a discovery service are mutually exclusive. You must +> provide configuration for one or the other, but not both. + +### Policy Image + +You can configure topaz to use a policy image stored in an OCI registry using the `opa.policy.oci` section. +At a minimum, you must specify the registry URL and full URI of the policy image to use. + +```yaml +opa: + policy: + oci: + registry: https://ghcr.io + image: ghcr.io/aserto-policies/policy-rebac:latest +``` + +If the image is stored in a private repository, you must also provide credentials to access it. +An API key or token is always required and, depending on the registry, you may also need to provide +a user name. +There are three ways to provide an API key: + +1. Plain text in `values.yaml`: +```yaml +opa: + policy: + oci: + registry: https://ghcr.io + image: ghcr.io/aserto-policies/policy-rebac:latest + apiKey: "" +``` + +2. Using the `--set` option when installing/upgrading the chart: +```shell +helm install ... --set opa.policy.oci.apiKey="" +``` + +3. Using a kubernetes secret: +```yaml +opa: + policy: + oci: + registry: https://ghcr.io + image: ghcr.io/aserto-policies/policy-rebac:latest + apiKeySecret: + name: "" + key: "" +``` + +### Discovery + +Configuration for a discovery service is done in the `opa.policy.discovery` section. +The discovery service requires an API key which can be provided in the same ways as for an OCI registry: +within `values.yaml`, using the `--set` option, or in a kubernetes secret. + +```yaml +opa: + policy: + discovery: + url: https://discovery.prod.aserto.com/api/v2/discovery + policyName: my-policy + tenantID: df61e407-cb84-491d-8a0c-942a68ba9f26 + apiKey: "" +``` + +> [!TIP] +> When using the hosted Aserto control plane, the discovery service URL and API key can be found in the +> [Aserto console](https://console.aserto.com) by navigating to the _Connections_ page and expanding +> the _Aserto Discovery_ connection. + +### Persistence + +For higher availability and faster restart times, you can configure topaz to store discovery responses +and downloaded policy images in a persistent volume. + +```yaml +opa: + persistence: + enabled: true +``` + +A 10MB volume is created by default but you can optionally specify the size and storage class: +```yaml +opa: + persistence: + enabled: true + storage: 20Mi + storageClassName: "" +``` + +See [here](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims) for +more information on persisten volume claims. + + +## Directory + +The `directory` section of `values.yaml` is used to configure the directory service that topaz uses to +store and manage its data. +By default, topaz run a local (edge) directory which can optionally be configured to sync data from a +central directory. Alternately, you can configure topaz to not run a local directory at all and instead +connect to a remote directory. + +> [!IMPORTANT] +> If configuration is provided for both edge and remote directories, topaz will use the remote directory. +> Configuration of the edge directory is ignored in this case. + +### Edge Directory + +The edge directory is a set of data-access services that run as part of topaz. The `model` and `reader` +services are always enabled when running an edge directory. The `writer`, `importer`, and `exporter` are +enabled by default but can be disabled if not needed. +For example, to only enable the `importer` service: + +```yaml +directory: + edge: + services: + - importer +``` + +Data is stored in a 1GB persistent volume by default. You can configure the size and storage class similar +to the OPA persistent volume configuration [above](#persistence). + +```yaml +directory: + edge: + persistence: + enabled: true + storage: 2Gi + storageClassName: "" +``` + +### Edge Sync + +The edge directory can be configured to sync data from a central directory. This is done by setting the +`directory.edge.sync` section in `values.yaml`. + +```yaml +directory: + edge: + sync: + address: directory.prod.aserto.com:8443 + tenantID: df61e407-cb84-491d-8a0c-942a68ba9f26 + apiKey: "" + # Skip verification of remote TLS certificate + skipTLSVerification: false + # The frequency of syncs in minutes. + intervalMinutes: 1 +``` + +> [!TIP] +> When using the hosted Aserto control plane, the directory API key can be found in the +> [Aserto console](https://console.aserto.com) by navigating to the _Connections_ page and expanding +> the _Aserto Directory_ connection. + + +### Remote Directory + +An alternative to syncing a local edge directory from a remote, is to directly call the remote directory +when topaz needs to access data. This is done by setting the `directory.remote` section in `values.yaml`. + +```yaml +directory: + remote: + address: directory.prod.aserto.com:8443 + tenantID: df61e407-cb84-491d-8a0c-942a68ba9f26 + apiKey: "" +``` + + +## Controller + +Topaz can optionally connect to a control plane allowing administrators to remotely force policy updates +and trigger directory syncs. The `controller` section of `values.yaml` is used to configure the connection +to the control plane. + +> [!NOTE] +> Before configuring the controller, you must create an _Edge Authorizer_ connection in the Aserto console +> and obtain the connection's mutual-TLS certificate and private key. +> See [here](https://docs.aserto.com/docs/edge-authorizers/security-and-management) for detailed instructions. + +```yaml +controller: + enabled: true + address: relay.prod.aserto.com:8443 + mtlsCert: | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + mtlsKey: | + -----BEGIN RSA PRIVATE KEY----- + ... + -----END RSA PRIVATE KEY----- + # [Optional] Kubernetes secret containing the mTLS client certificate and private key. + # Must be a secret of type kubernetes.io/tls. + mtlsCertSecretName: "" +``` + +Similar to other sensitive information, the mTLS certificate and private key can also be provided +in a kubernetes secret of type `kubernetes.io/tls`. + + +## Decision Logs + +Topaz can be configured to record a log of all authorization decisions it makes. +Decision logs can be written to a local file or shipped to a remote service. + +> [!IMPORTANT] +> If configuration is provided for both local and remote decision logging, topaz will use the remote configuration. +> Local file configuration is ignored in this case. + +### Local File + +To log decisions to a local file, set the `decisionLogs.file` section in `values.yaml`. + +```yaml +decisionLogs: + file: + enabled: true +``` + +Logs are written to the `/decisions` directory in the topaz pod. The directory is backed by a +100MB persistent volume by default. You can configure the size and storage class similar to the +OPA persistent volume configuration [above](#persistence). + +```yaml +decisionLogs: + persistence: + enabled: true + storage: 200Mi + storageClassName: "" +``` + +You can also configure the maximus size of a single log file and the number of log files to keep. + +```yaml +decisionLogs: + file: + maxFileSizeMB: 10 + maxFileCount: 10 +``` + +### Remote + +When a remote decision log service is used, topaz accumulates decisions in local files and periodically +ships them to the remote service in batches. In that case, the local `/decisions` directory is used as +the spool space for decisions waiting to be shipped. It is backed by a 100MB persistent volume by default +but the size and storage class can be configured similar to the OPA persistent volume configuration +[above](#persistence). + +Authentication to the remote service is done using mutual-TLS, similar to the [controller](#controller). +The same certificate and private key can be used for both services. + +```yaml +decisionLogs: + remote: + scribe: + address: ems.prod.aserto.com:8443 + tenantID: df61e407-cb84-491d-8a0c-942a68ba9f26 + mtlsCert: | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + mtlsKey: | + -----BEGIN RSA PRIVATE KEY----- + ... + -----END RSA PRIVATE KEY----- + # [Optional] Kubernetes secret containing the mTLS client certificate and private key. + # Must be a secret of type kubernetes.io/tls. + mtlsCertSecretName: "" + # [Optional] Duration (in seconds) to wait for a batch of decisions to be acknowledged by the server. + # If the server does not acknowledge the batch within this time, the batch is resent. + ackWaitSec: 60 +``` + +## Service Ports + +Topaz pods expose four ports: + +| Protocol | Default Port | Description | +|----------|--------------|-------------| +| gRPC | 8282 | gRPC services | +| HTTPS | 8383 | REST endpoints and web console | +| Health | 8484 | gRPC [health service](https://github.com/grpc/grpc/blob/master/doc/health-checking.md) | +| Metrics | 8585 | Prometheus metrics | + +The default ports can be overridden in `values.yaml`: + +```yaml +ports: + grpc: 9292 + https: 9393 + health: 9494 + metrics: 9595 +``` + +The metrics service can be disabled if not needed: + +```yaml +metrics: + enabled: false +``` + +## Authentication + +By default, anyone with access to the topaz pod can use the gRPC and REST endpoints. That means that any +service or job running in the same kubernetes cluster can access topaz. +To restrict access, you can configure topaz to require an API key for all service endpoints. +Multiple API keys can be configured making it possible to rotate keys without service interruption and to +provide separate keys for different clients. + +API keys are configured in the `auth` section of `values.yaml` and can be provided explicitly or using +Kubernetes secrets. + +```yaml +auth: + apiKeys: + - key: "" + - secretName: "<name of a kubernetes secret>" + secretKey: "<key within the secret>" +``` + +When one or more API keys are configured, clients must provide a key in the `Authorization` header of +all requests using the `Basic` scheme. For example, if port 8383 is forwarded from the topaz pod, you +can list all policy modules using: + +```shell +curl -k -H "Authorization: Basic <api-key>" https://localhost:8383/api/v2/policies +``` diff --git a/charts/topaz/templates/_helpers.tpl b/charts/topaz/templates/_helpers.tpl index 0efe2a6..16141e2 100644 --- a/charts/topaz/templates/_helpers.tpl +++ b/charts/topaz/templates/_helpers.tpl @@ -304,13 +304,7 @@ idle_timeout: {{ $cfg.idleTimeout | default "30s" }} {{- define "topaz.decisionLogger" -}} {{- with .Values.decisionLogs -}} -{{- if .file -}} -type: file -config: - log_file_path: /decisions/decisions.log - max_file_size_mb: {{ .file.maxFileSizeMB | default "50" }} - max_file_count: {{ .file.maxFileCount | default "2" }} -{{- else if .remote -}} +{{- if .remote -}} type: self config: store_directory: "/decisions" @@ -341,6 +335,12 @@ config: {{- toYaml . | toYaml | nindent 6 }} {{- end }} {{- end }} +{{- else if .remote -}} +type: file +config: + log_file_path: /decisions/decisions.log + max_file_size_mb: {{ .file.maxFileSizeMB | default "50" }} + max_file_count: {{ .file.maxFileCount | default "2" }} {{- else -}} {{- fail "either decisionLogs.file or decisionLogs.remote must be set" }} {{- end }} diff --git a/charts/topaz/values.yaml b/charts/topaz/values.yaml index 3e7afb7..f26f56d 100644 --- a/charts/topaz/values.yaml +++ b/charts/topaz/values.yaml @@ -122,11 +122,11 @@ controller: decisionLogs: enabled: false # The 'file' and 'remote' options are mutually exclusive. - file: {} - # # Write decision logs to a local file. - # # The logs are written to the spool directory (/decisions) and rotated when they reach the maximum size. - # maxFileSizeMB: 50 - # maxFileCount: 2 + file: + # Write decision logs to a local file. + # The logs are written to the spool directory (/decisions) and rotated when they reach the maximum size. + maxFileSizeMB: 50 + maxFileCount: 2 remote: {} # # Send decision logs to a remote scribe. # natsPort: 4222 From 11bac917317e0dbbda42a3d141de46325a8664e9 Mon Sep 17 00:00:00 2001 From: Ronen Hilewicz <ronen@aserto.com> Date: Wed, 9 Oct 2024 17:55:14 -0400 Subject: [PATCH 17/19] Link to topaz README --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index a1a24d3..3546a93 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ # Aserto Helm Charts +> [!NOTE] +> The documentation below discusses self-hosted deployment of the Aserto backend services. +> [See here](https://github.com/aserto-dev/helm/tree/main/charts/topaz) if you are +> looking to deploy a [topaz](https://www.topaz.sh) authorizer in your Kubernetes cluster. + [Aserto](https://www.aserto.com) is a cloud-native authorization service that provides fine-grained access control for your applications. From d1568992fe893867812a018f868b417f3c159c50 Mon Sep 17 00:00:00 2001 From: Ronen Hilewicz <ronen@aserto.com> Date: Wed, 9 Oct 2024 17:57:57 -0400 Subject: [PATCH 18/19] Topaz chart v0.1.0 --- charts/topaz/Chart.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/topaz/Chart.yaml b/charts/topaz/Chart.yaml index e790948..bdd1ec2 100644 --- a/charts/topaz/Chart.yaml +++ b/charts/topaz/Chart.yaml @@ -20,13 +20,13 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.0-1 +version: 0.1.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "0.32.26" +appVersion: "0.32.29" dependencies: - name: aserto-lib From 8afc7ad01ca989c539a03ea7d2411f2ce2e9f767 Mon Sep 17 00:00:00 2001 From: Ronen Hilewicz <ronen@aserto.com> Date: Thu, 10 Oct 2024 08:52:26 -0400 Subject: [PATCH 19/19] Fix decision log 'file'/'remote' mutual exclusion --- charts/topaz/templates/config.yaml | 5 +---- charts/topaz/values.yaml | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/charts/topaz/templates/config.yaml b/charts/topaz/templates/config.yaml index f19dede..f21dfde 100644 --- a/charts/topaz/templates/config.yaml +++ b/charts/topaz/templates/config.yaml @@ -84,10 +84,7 @@ stringData: tls_ca_cert_path: /https-certs/ca.crt {{- end }} - {{- if (.Values.decisionLogs).enabled -}} - {{- if (.Values.decisionLogs).file | and (.Values.decisionLogs).remote -}} - {{- fail "decisionLogs.file and decisionLogs.remote are mutually exclusive" }} - {{- end }} + {{- if (.Values.decisionLogs).enabled }} decision_logger: {{- include "topaz.decisionLogger" . | nindent 6 }} {{ end }} diff --git a/charts/topaz/values.yaml b/charts/topaz/values.yaml index f26f56d..3b69918 100644 --- a/charts/topaz/values.yaml +++ b/charts/topaz/values.yaml @@ -121,7 +121,7 @@ controller: decisionLogs: enabled: false - # The 'file' and 'remote' options are mutually exclusive. + # The 'file' and 'remote' options are mutually exclusive. If both are specified, 'remote' is used. file: # Write decision logs to a local file. # The logs are written to the spool directory (/decisions) and rotated when they reach the maximum size.