Skip to main content

Vault SSO Stack

The Vault SSO stack provides secure identity-backed secret access using HashiCorp Vault with Single Sign-On (SSO) integration. This stack deploys a complete Vault solution with External Secrets Operator for seamless Kubernetes integration.

Overview

The Vault SSO stack enables organizations to:

  • Centralize secret management with HashiCorp Vault
  • Implement SSO authentication using OIDC/SAML providers
  • Integrate with Kubernetes via External Secrets Operator
  • Maintain security best practices with proper authentication and authorization

Key Features

  • Cloud Agnostic - Works on any Kubernetes cluster
  • Complete Solution - Deploys both Vault and External Secrets Operator
  • SSO Integration - Supports OIDC and SAML authentication
  • Kubernetes Native - Uses ExternalSecret CRDs for integration
  • Production Ready - Follows security best practices

Architecture

The Vault SSO stack consists of several components working together:

Component Details

  1. Vault Server - Deployed in-cluster using the official HashiCorp Helm chart

    • Handles SSO authentication (OIDC/SAML)
    • Stores and manages secrets
    • Provides REST API and UI
  2. External Secrets Operator - Manages Kubernetes secret synchronization

    • Connects to Vault via SecretStore
    • Creates Kubernetes secrets from Vault data
    • Handles automatic refresh and updates
  3. SecretStore - Defines the connection to Vault

    • Configures authentication method
    • Specifies Vault server endpoint
    • Sets up access policies
  4. ExternalSecret - Defines which secrets to fetch

    • Maps Vault paths to Kubernetes secrets
    • Configures refresh intervals
    • Specifies target namespaces

Prerequisites

Before deploying the Vault SSO stack, ensure you have:

  • Kubernetes cluster with Helm support
  • SSO provider (OIDC/SAML) configured and accessible
  • kubectl configured to access your cluster
  • Vault CLI (optional, for administration)

SSO Provider Setup

You'll need to configure your SSO provider (e.g., Google, Okta, Auth0) with:

  • Client ID and Client Secret
  • Redirect URI: https://your-vault-domain/ui/vault/auth/oidc/oidc/callback
  • Scopes: openid, email, profile

Installation

1. Deploy the Stack

Apply the Vault SSO stack using your preferred method:

# Using kubectl and kustomize
kubectl apply -k kubezero/stacks/vault-sso

# Or using Argo CD (if configured)
kubectl apply -f - <<EOF
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: vault-sso
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/your-org/kubezero
targetRevision: main
path: kubezero/stacks/vault-sso
destination:
server: https://kubernetes.default.svc
namespace: vault
syncPolicy:
automated:
prune: true
selfHeal: true
EOF

2. Initialize Vault

After deployment, Vault needs to be initialized and unsealed:

# Port forward to access Vault
kubectl port-forward -n vault svc/vault 8200:8200

# In another terminal, initialize Vault
export VAULT_ADDR=http://localhost:8200
vault operator init

# Save the output - you'll need the keys and root token
# Unseal Vault (repeat 3 times with different keys)
vault operator unseal

# Login with root token
vault login

3. Configure SSO Authentication

Enable and configure OIDC authentication:

# Enable OIDC auth method
vault auth enable oidc

# Configure OIDC (replace with your provider details)
vault write auth/oidc/config \
oidc_discovery_url="https://accounts.google.com/.well-known/openid_configuration" \
oidc_client_id="your-client-id" \
oidc_client_secret="your-client-secret" \
default_role="default"

# Create OIDC role
vault write auth/oidc/role/default \
bound_audiences="your-client-id" \
allowed_redirect_uris="https://your-vault-domain/ui/vault/auth/oidc/oidc/callback" \
user_claim="email" \
policies="default"

4. Configure External Secrets Integration

Set up Kubernetes authentication for External Secrets Operator:

# Enable Kubernetes auth
vault auth enable kubernetes

# Create a role for External Secrets
vault write auth/kubernetes/role/external-secrets \
bound_service_account_names=external-secrets \
bound_service_account_namespaces=external-secrets \
policies=external-secrets-policy \
ttl=1h

# Create a policy for External Secrets
vault policy write external-secrets-policy -<<EOF
path "secret/data/*" {
capabilities = ["read"]
}
EOF

Configuration

Vault Configuration

The Vault module can be customized by modifying the Helm values in kubezero/modules/vault/helm-chart/helm-chart.yaml:

valuesInline:
server:
enabled: true
ha:
enabled: true # Enable high availability
replicas: 3
# Customize storage backend
# storage:
# file:
# path: /vault/data
ui:
enabled: true
serviceType: LoadBalancer # For external access

SecretStore Configuration

The SecretStore connects External Secrets Operator to Vault:

apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: vault-sso
namespace: external-secrets
spec:
provider:
vault:
server: "http://vault.vault.svc:8200"
path: "secret"
version: "v2"
auth:
kubernetes:
mountPath: "kubernetes"
role: "external-secrets"
serviceAccountRef:
name: external-secrets
namespace: external-secrets

ExternalSecret Examples

Basic Secret

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: database-credentials
namespace: my-app
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-sso
kind: SecretStore
target:
name: database-credentials
data:
- secretKey: username
remoteRef:
key: database/credentials
property: username
- secretKey: password
remoteRef:
key: database/credentials
property: password

Application Secrets

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: app-secrets
namespace: production
spec:
refreshInterval: 30m
secretStoreRef:
name: vault-sso
kind: SecretStore
target:
name: app-secrets
creationPolicy: Owner
data:
- secretKey: api-key
remoteRef:
key: apps/my-app
property: api_key
- secretKey: jwt-secret
remoteRef:
key: apps/my-app
property: jwt_secret
- secretKey: database-url
remoteRef:
key: apps/my-app
property: database_url

Usage

Accessing Vault UI

  1. Port forward to access the Vault UI:

    kubectl port-forward -n vault svc/vault 8200:8200
  2. Open browser and navigate to http://localhost:8200

  3. Login using your SSO provider

Managing Secrets

Via Vault UI

  1. Navigate to the Secrets tab
  2. Click Create secret
  3. Enter the path (e.g., secret/apps/my-app)
  4. Add key-value pairs
  5. Click Save

Via Vault CLI

# Store a secret
vault kv put secret/apps/my-app \
api_key="your-api-key" \
database_url="postgresql://user:pass@host:5432/db"

# Retrieve a secret
vault kv get secret/apps/my-app

# List secrets
vault kv list secret/apps/

Monitoring

Check the status of External Secrets:

# List ExternalSecrets
kubectl get externalsecrets -A

# Check ExternalSecret status
kubectl describe externalsecret database-credentials -n my-app

# View External Secrets Operator logs
kubectl logs -n external-secrets deployment/external-secrets

Security Considerations

Authentication

  • Use strong SSO providers with MFA enabled
  • Regularly rotate OIDC client secrets
  • Limit redirect URIs to trusted domains
  • Use least privilege policies for Vault roles

Authorization

  • Create specific policies for different applications
  • Use namespace isolation for ExternalSecrets
  • Regularly audit Vault access logs
  • Implement secret rotation policies

Network Security

  • Use TLS for Vault communication
  • Restrict network access to Vault services
  • Use service mesh for internal communication
  • Monitor network traffic for anomalies

Troubleshooting

Common Issues

Vault Unsealed

# Check Vault status
kubectl get pods -n vault
kubectl logs -n vault deployment/vault

# Unseal Vault
vault operator unseal

External Secrets Not Syncing

# Check SecretStore status
kubectl describe secretstore vault-sso -n external-secrets

# Verify Vault connectivity
kubectl exec -n external-secrets deployment/external-secrets -- \
curl -s http://vault.vault.svc:8200/v1/sys/health

# Check ExternalSecret status
kubectl describe externalsecret <name> -n <namespace>

SSO Authentication Issues

  1. Verify OIDC configuration:

    vault read auth/oidc/config
  2. Check redirect URIs match your Vault domain

  3. Verify client credentials are correct

  4. Check Vault logs for authentication errors

Debug Commands

# Check Vault status
vault status

# List auth methods
vault auth list

# Test OIDC configuration
vault read auth/oidc/config

# Check Kubernetes auth
vault read auth/kubernetes/role/external-secrets

# View Vault policies
vault policy list
vault policy read external-secrets-policy

Best Practices

Secret Management

  • Use structured paths (e.g., secret/apps/<app-name>)
  • Implement secret rotation policies
  • Use different namespaces for different environments
  • Regularly audit secret access

Access Control

  • Create specific roles for each application
  • Use namespace-based access control
  • Implement time-based access (TTL)
  • Regularly review and update policies

Monitoring and Alerting

  • Monitor Vault metrics and logs
  • Set up alerts for failed authentication
  • Track secret access patterns
  • Monitor External Secrets sync status

References