API_KEY = "sk-prod-293847239847"
API_KEY = "sk-prod-293847239847"
API_KEY = "sk-prod-293847239847"
prod-admin / password123
prod-admin / password123
prod-admin / password123
No attribution
No least privilege
No revocation granularity
No attribution
No least privilege
No revocation granularity
No attribution
No least privilege
No revocation granularity
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
echo "cGFzc3dvcmQ=" | base64 -d
echo "cGFzc3dvcmQ=" | base64 -d
echo "cGFzc3dvcmQ=" | base64 -d
password
Stop distributing credentials.
Start distributing identity.
Stop distributing credentials.
Start distributing identity.
Stop distributing credentials.
Start distributing identity.
Pod → authenticated identity → temporary credentials
Pod → authenticated identity → temporary credentials
Pod → authenticated identity → temporary credentials
resource "aws_iam_role" "payment_service" { name = "payment-service-role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{ Effect = "Allow" Principal = { Federated = aws_iam_openid_connect_provider.eks.arn } Action = "sts:AssumeRoleWithWebIdentity" Condition = { StringEquals = { "${replace( aws_eks_cluster.main.identity[0].oidc[0].issuer, "https://", "" )}:sub" = "system:serviceaccount:payments:payment-service" } } }] })
}
resource "aws_iam_role" "payment_service" { name = "payment-service-role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{ Effect = "Allow" Principal = { Federated = aws_iam_openid_connect_provider.eks.arn } Action = "sts:AssumeRoleWithWebIdentity" Condition = { StringEquals = { "${replace( aws_eks_cluster.main.identity[0].oidc[0].issuer, "https://", "" )}:sub" = "system:serviceaccount:payments:payment-service" } } }] })
}
resource "aws_iam_role" "payment_service" { name = "payment-service-role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{ Effect = "Allow" Principal = { Federated = aws_iam_openid_connect_provider.eks.arn } Action = "sts:AssumeRoleWithWebIdentity" Condition = { StringEquals = { "${replace( aws_eks_cluster.main.identity[0].oidc[0].issuer, "https://", "" )}:sub" = "system:serviceaccount:payments:payment-service" } } }] })
}
apiVersion: v1
kind: ServiceAccount metadata: name: payment-service namespace: payments annotations: eks.amazonaws.com/role-arn: arn:aws:iam::ACCOUNT:role/payment-service-role
apiVersion: v1
kind: ServiceAccount metadata: name: payment-service namespace: payments annotations: eks.amazonaws.com/role-arn: arn:aws:iam::ACCOUNT:role/payment-service-role
apiVersion: v1
kind: ServiceAccount metadata: name: payment-service namespace: payments annotations: eks.amazonaws.com/role-arn: arn:aws:iam::ACCOUNT:role/payment-service-role
Kubernetes Service Account
↔
Google Service Account
Kubernetes Service Account
↔
Google Service Account
Kubernetes Service Account
↔
Google Service Account
Application requests PostgreSQL credentials
↓
Vault creates short-lived DB user
↓
Credentials expire automatically
Application requests PostgreSQL credentials
↓
Vault creates short-lived DB user
↓
Credentials expire automatically
Application requests PostgreSQL credentials
↓
Vault creates short-lived DB user
↓
Credentials expire automatically
vault auth enable kubernetes
vault auth enable kubernetes
vault auth enable kubernetes
vault write auth/kubernetes/role/payment-api \ bound_service_account_names=payment-service \ bound_service_account_namespaces=payments \ policies=payment-read \ ttl=1h
vault write auth/kubernetes/role/payment-api \ bound_service_account_names=payment-service \ bound_service_account_namespaces=payments \ policies=payment-read \ ttl=1h
vault write auth/kubernetes/role/payment-api \ bound_service_account_names=payment-service \ bound_service_account_namespaces=payments \ policies=payment-read \ ttl=1h
vault read database/creds/payment-role
vault read database/creds/payment-role
vault read database/creds/payment-role
{ "username": "v-token-abc123", "password": "generated-secret", "lease_duration": 3600
}
{ "username": "v-token-abc123", "password": "generated-secret", "lease_duration": 3600
}
{ "username": "v-token-abc123", "password": "generated-secret", "lease_duration": 3600
}
Kubernetes Secret
← synced from →
Vault / AWS Secrets Manager / GCP Secret Manager
Kubernetes Secret
← synced from →
Vault / AWS Secrets Manager / GCP Secret Manager
Kubernetes Secret
← synced from →
Vault / AWS Secrets Manager / GCP Secret Manager
helm install external-secrets external-secrets/external-secrets
helm install external-secrets external-secrets/external-secrets
helm install external-secrets external-secrets/external-secrets
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret metadata: name: payment-api-secret spec: refreshInterval: 1h secretStoreRef: name: aws-secret-store kind: SecretStore target: name: payment-api-secret data: - secretKey: api-key remoteRef: key: prod/payment-api property: api_key
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret metadata: name: payment-api-secret spec: refreshInterval: 1h secretStoreRef: name: aws-secret-store kind: SecretStore target: name: payment-api-secret data: - secretKey: api-key remoteRef: key: prod/payment-api property: api_key
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret metadata: name: payment-api-secret spec: refreshInterval: 1h secretStoreRef: name: aws-secret-store kind: SecretStore target: name: payment-api-secret data: - secretKey: api-key remoteRef: key: prod/payment-api property: api_key
How do you store encrypted secrets safely in Git?
How do you store encrypted secrets safely in Git?
How do you store encrypted secrets safely in Git?
kubectl create secret generic app-secret
kubectl create secret generic app-secret
kubectl create secret generic app-secret
kubeseal --format yaml
kubeseal --format yaml
kubeseal --format yaml
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
Generate → use → expire automatically
Generate → use → expire automatically
Generate → use → expire automatically
RotationRules: AutomaticallyAfterDays: 30
RotationRules: AutomaticallyAfterDays: 30
RotationRules: AutomaticallyAfterDays: 30
Secret rotated
↓
Application breaks
Secret rotated
↓
Application breaks
Secret rotated
↓
Application breaks
vault audit enable file file_path=/var/log/vault_audit.log
vault audit enable file file_path=/var/log/vault_audit.log
vault audit enable file file_path=/var/log/vault_audit.log
Kubernetes Workload ↓
IRSA / Workload Identity ↓
Vault / Cloud Secret Manager ↓
External Secrets Operator ↓
Application Runtime
Kubernetes Workload ↓
IRSA / Workload Identity ↓
Vault / Cloud Secret Manager ↓
External Secrets Operator ↓
Application Runtime
Kubernetes Workload ↓
IRSA / Workload Identity ↓
Vault / Cloud Secret Manager ↓
External Secrets Operator ↓
Application Runtime
Identity over credentials
Temporary over permanent
Dynamic over static
Automated over manual
Auditable over opaque
Identity over credentials
Temporary over permanent
Dynamic over static
Automated over manual
Auditable over opaque
Identity over credentials
Temporary over permanent
Dynamic over static
Automated over manual
Auditable over opaque - Enterprises
- Government systems
- Fortune 500 infrastructure - Cloud-native identity systems
- Kubernetes secret abstractions
- External Secrets Operator
- Sealed Secrets
- Workload identity federation
- Dynamic credentials - Git history preserves it
- Forks replicate it
- CI logs may expose it
- Developers clone it locally
- Backups persist it indefinitely - Automation tools
- Contractors - GitHub Actions
- Kubernetes Secrets
- Terraform variables - Encryption at rest
- Admission policies
- Audit logging - No static AWS keys
- Automatic credential rotation
- IAM-native permissions
- Short-lived credentials
- Excellent auditability - Third-party APIs
- Cross-cloud systems
- Legacy applications
- Dynamic credential issuance
- Multi-cluster secret orchestration - HA clustering
- Storage backend
- Unseal process
- Disaster recovery
- Performance replication - Kubernetes-native
- GitOps-friendly
- Central secret backend
- Automatic refresh
- Cleaner operational model - Dynamic DB users
- Certificate issuance
- Secret leasing
- PKI workflows - GitOps-compatible
- Easy onboarding
- No external dependency - Static secrets only
- No automatic rotation
- Kubernetes-scoped
- No dynamic credential issuance - Who accessed this secret?
- From which workload?
- Was it expected?
- Was it anomalous? - Hardcoded credentials
- Kubernetes Secrets
- Shared accounts - AWS Secrets Manager
- GCP Secret Manager - Vault Agent Injector - Old credentials
- Shared passwords
- Long-lived tokens