Skip to content

Securing Credentials in .NET Applications with Docker and Kubernetes

This guide covers best practices for securing credentials in .NET applications, particularly when deployed to Docker containers and Kubernetes environments.

Table of Contents

Local Development: Removing Credentials from Settings Files

Remove sensitive credentials from your configuration files to keep them out of source control:

appsettings.json

json
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "SMTP": {
    "Host": "",
    "Port": 25,
    "EnableSsl": true
    // Credentials removed and will be loaded from secure sources
  }
}

appsettings.Development.json

json
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "SMTP": {
    "Host": "sandbox.smtp.mailtrap.io",
    "Port": 2525,
    "EnableSsl": true
    // Credentials removed and will be loaded from secure sources
  }
}

Loading Credentials Securely in .NET

Update your .NET application to load credentials from environment variables or user secrets:

csharp
// From Program.cs
var mailConfig = new Config();
builder.Configuration.GetSection("SMTP").Bind(mailConfig);

// Load credentials from environment variables (production) or user secrets (development)
mailConfig.User = Environment.GetEnvironmentVariable("SMTP__User") ??
                  builder.Configuration["SMTP:User"] ??
                  mailConfig.User;

mailConfig.Pass = Environment.GetEnvironmentVariable("SMTP__Pass") ??
                  builder.Configuration["SMTP:Pass"] ??
                  mailConfig.Pass;

builder.Services.AddSingleton(mailConfig);

Setting Up .NET User Secrets

For local development, use .NET's user secrets:

bash
# Initialize user secrets for your project

cd src/HandOver/WebApi

dotnet user-secrets init --project HandOverApi.csproj

# Add your SMTP credentials to user secrets
dotnet user-secrets set "SMTP:User" "XXX" --project HandOverApi.csproj
dotnet user-secrets set "SMTP:Pass" "XXX" --project HandOverApi.csproj


dotnet user-secrets set "SMTP:User" "00f0fa8e9fb44e" --project HandOverApi.csproj
dotnet user-secrets set "SMTP:Pass" "eae4f504920a28" --project HandOverApi.csproj

Using Kubernetes Secrets

Create a Kubernetes Secret to store your credentials:

yaml
# kubernetes/smtp-credentials.yaml
apiVersion: v1
kind: Secret
metadata:
  name: smtp-credentials
type: Opaque
data:
  # Base64 encoded credentials - DO NOT COMMIT THIS FILE
  smtp-user: 00f0fa8e9fb44e  # Replace with actual base64 encoded username
  smtp-pass: eae4f504920a28  # Replace with actual base64 encoded password

Generate base64 encoded values for your secrets:

bash
# Convert credentials to base64
echo -n "your-smtp-username" | base64
echo -n "your-smtp-password" | base64

# Create the secret in your Kubernetes cluster
kubectl apply -f kubernetes/smtp-credentials.yaml

Setting Up Kubernetes Deployments

Configure your Kubernetes deployment to use the secrets:

yaml
# kubernetes/handover-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: handover-api
  labels:
    app: handover-api
spec:
  replicas: 1
  selector:
    matchLabels:
      app: handover-api
  template:
    metadata:
      labels:
        app: handover-api
    spec:
      containers:
      - name: handover-api
        image: handover-api:latest
        ports:
        - containerPort: 80
        env:
        - name: SMTP__User
          valueFrom:
            secretKeyRef:
              name: smtp-credentials
              key: smtp-user
        - name: SMTP__Pass
          valueFrom:
            secretKeyRef:
              name: smtp-credentials
              key: smtp-pass

Development Workflow with KinD

For local Kubernetes development, use KinD (Kubernetes in Docker):

bash
# Create a KinD cluster
kind create cluster --name handover-dev

# Apply your secrets
kubectl apply -f kubernetes/smtp-credentials.yaml

# Build and load your Docker image into KinD
docker build -t handover-api:latest .
kind load docker-image handover-api:latest --name handover-dev

# Deploy your application
kubectl apply -f kubernetes/handover-deployment.yaml

Advanced Options for Production

Sealed Secrets for GitOps

For GitOps workflows, use Sealed Secrets to securely commit encrypted secrets to Git:

bash
# Install the Sealed Secrets controller
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.19.5/controller.yaml

# Install kubeseal CLI
wget https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.19.5/kubeseal-0.19.5-linux-amd64.tar.gz
tar -xvzf kubeseal-0.19.5-linux-amd64.tar.gz
sudo install -m 755 kubeseal /usr/local/bin/kubeseal

# Create a sealed secret
kubectl create secret generic smtp-credentials \
  --from-literal=smtp-user=your-username \
  --from-literal=smtp-pass=your-password \
  --dry-run=client -o yaml | \
  kubeseal --format yaml > kubernetes/sealed-smtp-credentials.yaml

# Apply the sealed secret (this is safe to commit to git)
kubectl apply -f kubernetes/sealed-smtp-credentials.yaml

HashiCorp Vault Integration

For enterprise environments, use HashiCorp Vault:

bash
# Install Vault using Helm
helm repo add hashicorp https://helm.releases.hashicorp.com
helm install vault hashicorp/vault

# Example Pod using Vault Agent Injector
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: handover-api
  labels:
    app: handover-api
spec:
  replicas: 1
  selector:
    matchLabels:
      app: handover-api
  template:
    metadata:
      labels:
        app: handover-api
      annotations:
        vault.hashicorp.com/agent-inject: 'true'
        vault.hashicorp.com/role: 'handover-api'
        vault.hashicorp.com/agent-inject-secret-smtp.env: 'secret/data/smtp'
        vault.hashicorp.com/agent-inject-template-smtp.env: |
          {{- with secret "secret/data/smtp" -}}
          export SMTP__User="{{ .Data.data.user }}"
          export SMTP__Pass="{{ .Data.data.pass }}"
          {{- end -}}
    spec:
      containers:
      - name: handover-api
        image: handover-api:latest
EOF

Best Practices

  1. Never store secrets in code or images

    • Keep credentials out of source control
    • Don't bake secrets into Docker images
  2. Use dedicated secret management tools

    • Development: .NET User Secrets
    • Production: Kubernetes Secrets, Vault, or cloud providers' secret management services
  3. Limit access to secrets

    • Use Kubernetes RBAC to control who can view and manage secrets
    • Implement the principle of least privilege
  4. Rotate credentials regularly

    • Set up a process for credential rotation
    • Automate rotation where possible
  5. Encrypt secrets at rest

    • Ensure your Kubernetes etcd is encrypted
    • Use additional encryption tools when needed
  6. Audit secret access

    • Enable audit logging for secret access
    • Monitor for unauthorized access attempts
  7. Consider managed services

    • For production, consider AWS Secrets Manager, Azure Key Vault, or Google Secret Manager
  8. Separate development and production secrets

    • Use different secrets for different environments
    • Never use production credentials in development