Add support for existing Secrets and External Secrets Operator
Some checks failed
Helm Chart Build / lint-only (push) Has been skipped
Helm Chart Build / build-helm (push) Failing after 9s
Build and Deploy / build-api (push) Successful in 51s
Build and Deploy / build-web (push) Successful in 1m3s

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 <noreply@anthropic.com>
This commit is contained in:
d.viti
2025-10-09 15:53:38 +02:00
parent f5a4071b71
commit 694709ae9a
5 changed files with 370 additions and 7 deletions

View File

@@ -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/)

View File

@@ -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 }}

View File

@@ -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

View File

@@ -1,4 +1,4 @@
{{- if .Values.api7.enabled }}
{{- if and .Values.api7.enabled (not .Values.api7.gateway.existingSecret) }}
apiVersion: v1
kind: Secret
metadata:

View File

@@ -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