From 694709ae9a38dd05f323ae4c84244624727f1e56 Mon Sep 17 00:00:00 2001 From: "d.viti" Date: Thu, 9 Oct 2025 15:53:38 +0200 Subject: [PATCH] Add support for existing Secrets and External Secrets Operator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enhanced secret management for API7 Gateway credentials with support for existing Secrets and External Secrets Operator integration. Changes: 1. Secret Configuration: - Added api7.gateway.existingSecret parameter for using existing secrets - Added api7.gateway.existingSecretKeys for custom key names - Modified secret-api7.yaml to only create secret if existingSecret is empty - Updated job-adc-sync.yaml to reference configurable secret name 2. Values.yaml Documentation: - Added comprehensive documentation for secret configuration options - Documented two approaches: inline config (dev) vs existing secret (prod) - Added example kubectl command for creating secrets manually - Included instructions for obtaining admin key from API7 EE 3. External Secrets Support: - Created externalsecret-api7.yaml.example with complete examples - Included examples for AWS Secrets Manager and HashiCorp Vault - Documented SecretStore configuration patterns 4. Documentation: - Created SECRET-MANAGEMENT.md comprehensive guide - Covered all secret management options (inline, manual, external) - Added security best practices and troubleshooting guide - Included examples for External Secrets Operator setup Benefits: - Improved security: Secrets not stored in values.yaml - Flexibility: Support for any secret management tool - Production-ready: Works with External Secrets Operator - Better practices: Clear separation of config vs secrets 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- helm/api7ee-demo-k8s/SECRET-MANAGEMENT.md | 233 ++++++++++++++++++ .../externalsecret-api7.yaml.example | 93 +++++++ .../templates/job-adc-sync.yaml | 12 +- .../templates/secret-api7.yaml | 2 +- helm/api7ee-demo-k8s/values.yaml | 37 +++ 5 files changed, 370 insertions(+), 7 deletions(-) create mode 100644 helm/api7ee-demo-k8s/SECRET-MANAGEMENT.md create mode 100644 helm/api7ee-demo-k8s/templates/externalsecret-api7.yaml.example diff --git a/helm/api7ee-demo-k8s/SECRET-MANAGEMENT.md b/helm/api7ee-demo-k8s/SECRET-MANAGEMENT.md new file mode 100644 index 0000000..dc09e31 --- /dev/null +++ b/helm/api7ee-demo-k8s/SECRET-MANAGEMENT.md @@ -0,0 +1,233 @@ +# Secret Management for API7 Gateway + +This document explains how to manage API7 Gateway credentials securely. + +## Overview + +API7 Gateway requires the following credentials: +- **Admin URL**: Dashboard admin API endpoint +- **Admin Key**: Authentication token for admin API +- **Gateway Group**: Logical grouping of gateway instances + +## Configuration Options + +### Option 1: Inline Configuration (Development Only) + +**⚠️ NOT RECOMMENDED for production** + +Credentials are stored directly in `values.yaml`: + +```yaml +api7: + gateway: + existingSecret: "" # Leave empty + adminUrl: https://api7ee3-0-1759339083-dashboard:7443 + adminKey: "your-admin-key" + group: default +``` + +The chart will create a Kubernetes Secret automatically. + +### Option 2: Existing Secret (Recommended) + +**✅ RECOMMENDED for production** + +Create a Secret manually or using a secret management tool, then reference it: + +```yaml +api7: + gateway: + existingSecret: "api7-credentials" # Name of your secret + existingSecretKeys: + adminUrl: admin-url + adminKey: admin-key + group: gateway-group +``` + +#### Create Secret Manually + +```bash +kubectl create secret generic api7-credentials \ + --from-literal=admin-url=https://api7ee3-0-1759339083-dashboard:7443 \ + --from-literal=admin-key=YOUR_ADMIN_KEY \ + --from-literal=gateway-group=default \ + -n api7ee +``` + +#### Get Admin Key from API7 Enterprise + +```bash +# Get admin key from API7 Enterprise installation +kubectl get secret -n api7ee api7ee3-0-1759339083 \ + -o jsonpath='{.data.admin_key}' | base64 -d +``` + +### Option 3: External Secrets Operator + +**✅ RECOMMENDED for production with centralized secret management** + +Use External Secrets Operator to sync secrets from external providers like: +- AWS Secrets Manager +- HashiCorp Vault +- Azure Key Vault +- GCP Secret Manager +- And more... + +#### Step 1: Install External Secrets Operator + +```bash +helm repo add external-secrets https://charts.external-secrets.io +helm install external-secrets external-secrets/external-secrets -n external-secrets-system --create-namespace +``` + +#### Step 2: Configure SecretStore + +Example for HashiCorp Vault: + +```yaml +apiVersion: external-secrets.io/v1beta1 +kind: SecretStore +metadata: + name: vault-backend + namespace: api7ee +spec: + provider: + vault: + server: "https://vault.example.com" + path: "secret" + version: "v2" + auth: + kubernetes: + mountPath: "kubernetes" + role: "api7-role" + serviceAccountRef: + name: api7ee-demo-api7ee-demo-k8s +``` + +#### Step 3: Create ExternalSecret + +See `templates/externalsecret-api7.yaml.example` for a complete example. + +```yaml +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: api7-credentials-external + namespace: api7ee +spec: + refreshInterval: 1h + secretStoreRef: + name: vault-backend + kind: SecretStore + target: + name: api7-credentials + creationPolicy: Owner + data: + - secretKey: admin-url + remoteRef: + key: api7/gateway + property: admin_url + - secretKey: admin-key + remoteRef: + key: api7/gateway + property: admin_key + - secretKey: gateway-group + remoteRef: + key: api7/gateway + property: gateway_group +``` + +#### Step 4: Configure Helm Values + +```yaml +api7: + gateway: + existingSecret: "api7-credentials" # Created by ExternalSecret +``` + +## Secret Keys + +The Secret must contain these keys (default names): + +| Key | Description | Example | +|-----|-------------|---------| +| `admin-url` | Dashboard admin API URL | `https://api7ee3-0-1759339083-dashboard:7443` | +| `admin-key` | Dashboard admin API key | `edd1c9f034335f136f87ad84b625c8f1` | +| `gateway-group` | Gateway group name | `default` | + +### Custom Key Names + +If your Secret uses different key names, configure them: + +```yaml +api7: + gateway: + existingSecret: "my-custom-secret" + existingSecretKeys: + adminUrl: dashboard_url # Your custom key name + adminKey: api_token # Your custom key name + group: group_name # Your custom key name +``` + +## Security Best Practices + +1. **Never commit secrets to Git** + - Use `.gitignore` for values files containing secrets + - Use secret management tools for production + +2. **Use RBAC to restrict secret access** + - Limit which ServiceAccounts can read secrets + - Use namespace isolation + +3. **Rotate credentials regularly** + - Update admin keys periodically + - Use External Secrets Operator for automatic rotation + +4. **Enable audit logging** + - Monitor secret access in Kubernetes audit logs + - Alert on unauthorized access attempts + +5. **Use encryption at rest** + - Enable Kubernetes secret encryption + - Use external KMS for additional security + +## Troubleshooting + +### Secret not found + +```bash +# Check if secret exists +kubectl get secret -n api7ee + +# Describe the secret +kubectl describe secret api7-credentials -n api7ee +``` + +### Invalid credentials + +```bash +# View secret data (base64 encoded) +kubectl get secret api7-credentials -n api7ee -o yaml + +# Decode and verify values +kubectl get secret api7-credentials -n api7ee \ + -o jsonpath='{.data.admin-key}' | base64 -d +``` + +### ADC sync job fails + +```bash +# Check job logs +kubectl logs -n api7ee job/api7ee-demo-api7ee-demo-k8s-adc-sync + +# Common issues: +# - Wrong admin URL (check DNS resolution) +# - Invalid admin key (verify key is correct) +# - TLS certificate issues (use tlsSkipVerify: true for self-signed) +``` + +## References + +- [External Secrets Operator Documentation](https://external-secrets.io/) +- [Kubernetes Secrets](https://kubernetes.io/docs/concepts/configuration/secret/) +- [API7 Enterprise Documentation](https://docs.api7.ai/enterprise/) diff --git a/helm/api7ee-demo-k8s/templates/externalsecret-api7.yaml.example b/helm/api7ee-demo-k8s/templates/externalsecret-api7.yaml.example new file mode 100644 index 0000000..84e468c --- /dev/null +++ b/helm/api7ee-demo-k8s/templates/externalsecret-api7.yaml.example @@ -0,0 +1,93 @@ +# Example ExternalSecret for API7 Gateway credentials +# This file is not deployed by default - it serves as an example. +# +# To use External Secrets Operator: +# 1. Install External Secrets Operator in your cluster +# 2. Configure a SecretStore (e.g., AWS Secrets Manager, Vault, etc.) +# 3. Rename this file to remove .example extension +# 4. Set api7.gateway.existingSecret to the secret name below +# 5. Adjust the backend configuration to match your SecretStore +# +# Documentation: https://external-secrets.io/ + +{{- if false }} # Change to 'if .Values.api7.gateway.useExternalSecret' to enable +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: {{ include "api7ee.fullname" . }}-api7-admin-external + labels: + {{- include "api7ee.labels" . | nindent 4 }} + app.kubernetes.io/component: api7 +spec: + # Refresh interval for fetching secrets from external provider + refreshInterval: 1h + + # Reference to SecretStore + secretStoreRef: + name: vault-backend # Name of your SecretStore + kind: SecretStore # or ClusterSecretStore + + # Target Secret configuration + target: + name: {{ include "api7ee.fullname" . }}-api7-admin + creationPolicy: Owner + template: + type: Opaque + data: + # Map external secret keys to Kubernetes secret keys + admin-url: "{{ `{{ .adminUrl }}` }}" + admin-key: "{{ `{{ .adminKey }}` }}" + gateway-group: "{{ `{{ .group }}` }}" + + # Data to fetch from external provider + data: + - secretKey: adminUrl + remoteRef: + key: api7/gateway # Path in external secret store + property: admin_url # Property name + + - secretKey: adminKey + remoteRef: + key: api7/gateway + property: admin_key + + - secretKey: group + remoteRef: + key: api7/gateway + property: gateway_group + +--- +# Example for AWS Secrets Manager +# apiVersion: external-secrets.io/v1beta1 +# kind: SecretStore +# metadata: +# name: aws-secretsmanager +# spec: +# provider: +# aws: +# service: SecretsManager +# region: us-east-1 +# auth: +# jwt: +# serviceAccountRef: +# name: external-secrets-sa + +--- +# Example for HashiCorp Vault +# apiVersion: external-secrets.io/v1beta1 +# kind: SecretStore +# metadata: +# name: vault-backend +# spec: +# provider: +# vault: +# server: "https://vault.example.com" +# path: "secret" +# version: "v2" +# auth: +# kubernetes: +# mountPath: "kubernetes" +# role: "api7-role" +# serviceAccountRef: +# name: {{ include "api7ee.serviceAccountName" . }} +{{- end }} diff --git a/helm/api7ee-demo-k8s/templates/job-adc-sync.yaml b/helm/api7ee-demo-k8s/templates/job-adc-sync.yaml index d4291af..621aaea 100644 --- a/helm/api7ee-demo-k8s/templates/job-adc-sync.yaml +++ b/helm/api7ee-demo-k8s/templates/job-adc-sync.yaml @@ -47,18 +47,18 @@ spec: - name: API7_ADMIN_URL valueFrom: secretKeyRef: - name: {{ include "api7ee.fullname" . }}-api7-admin - key: admin-url + name: {{ .Values.api7.gateway.existingSecret | default (printf "%s-api7-admin" (include "api7ee.fullname" .)) }} + key: {{ .Values.api7.gateway.existingSecretKeys.adminUrl | default "admin-url" }} - name: API7_ADMIN_KEY valueFrom: secretKeyRef: - name: {{ include "api7ee.fullname" . }}-api7-admin - key: admin-key + name: {{ .Values.api7.gateway.existingSecret | default (printf "%s-api7-admin" (include "api7ee.fullname" .)) }} + key: {{ .Values.api7.gateway.existingSecretKeys.adminKey | default "admin-key" }} - name: API7_GATEWAY_GROUP valueFrom: secretKeyRef: - name: {{ include "api7ee.fullname" . }}-api7-admin - key: gateway-group + name: {{ .Values.api7.gateway.existingSecret | default (printf "%s-api7-admin" (include "api7ee.fullname" .)) }} + key: {{ .Values.api7.gateway.existingSecretKeys.group | default "gateway-group" }} volumeMounts: - name: adc-config mountPath: /config diff --git a/helm/api7ee-demo-k8s/templates/secret-api7.yaml b/helm/api7ee-demo-k8s/templates/secret-api7.yaml index 11ea004..56cde6b 100644 --- a/helm/api7ee-demo-k8s/templates/secret-api7.yaml +++ b/helm/api7ee-demo-k8s/templates/secret-api7.yaml @@ -1,4 +1,4 @@ -{{- if .Values.api7.enabled }} +{{- if and .Values.api7.enabled (not .Values.api7.gateway.existingSecret) }} apiVersion: v1 kind: Secret metadata: diff --git a/helm/api7ee-demo-k8s/values.yaml b/helm/api7ee-demo-k8s/values.yaml index 674b0da..76d1530 100644 --- a/helm/api7ee-demo-k8s/values.yaml +++ b/helm/api7ee-demo-k8s/values.yaml @@ -258,6 +258,40 @@ api7: # API7 Gateway Connection Settings gateway: + # ======================================================================== + # Secret Configuration + # ======================================================================== + # Option 1: Use existing Secret (recommended for production) + # Provide the name of an existing Kubernetes Secret containing credentials. + # This is useful when using External Secrets Operator, Sealed Secrets, + # or manually managed secrets for better security. + # + # The secret must contain these keys (or customize with existingSecretKeys): + # - admin-url: Dashboard admin API URL + # - admin-key: Dashboard admin API key + # - gateway-group: Gateway group name + # + # Example: Create secret manually: + # kubectl create secret generic api7-credentials \ + # --from-literal=admin-url=https://api7ee3-0-1759339083-dashboard:7443 \ + # --from-literal=admin-key=YOUR_ADMIN_KEY \ + # --from-literal=gateway-group=default \ + # -n api7ee + existingSecret: "" # Name of existing secret (leave empty to create new secret) + + # Custom key names for existing secret (optional) + # Only needed if your existing secret uses different key names + existingSecretKeys: + adminUrl: admin-url # Key name for admin URL + adminKey: admin-key # Key name for admin key + group: gateway-group # Key name for gateway group + + # ======================================================================== + # Option 2: Inline Configuration (for development only) + # ======================================================================== + # When existingSecret is empty, a Secret will be created with these values. + # NOT RECOMMENDED for production - use existingSecret instead! + # Dashboard Admin API URL (HTTPS required for API7 Enterprise) # The dashboard service exposes the admin API on port 7443 adminUrl: https://api7ee3-0-1759339083-dashboard:7443 @@ -269,6 +303,9 @@ api7: # Gateway group name (logical grouping of gateway instances) group: default + # ======================================================================== + # Gateway Service Configuration + # ======================================================================== # Gateway service name (for traffic routing) # This is the Kubernetes service that routes traffic to APISIX data plane gatewayService: gateway-0-1759393614-gateway