Files
vault/README.md
ducoterra 625474bed4 Add AWS auth and secret docs
Add docs to README explaining how to enable and use aws auth and aws
client secrets.
2022-01-10 16:54:01 -05:00

27 KiB

Vault

Prereqs

brew tap hashicorp/tap
brew install hashicorp/tap/vault

brew install jq

Install (bare metal)

  1. Download Vault

  2. Create a vault user

    useradd --system --home /etc/vault.d --shell /bin/false vault
    
  3. Create a config file

    mkdir -p /etc/vault.d
    touch /etc/vault.d/vault.hcl
    chmod 640 /etc/vault.d/vault.hcl
    chown --recursive vault:vault /etc/vault.d
    
  4. Add the following

    storage "file" {
      path = "/vault/data"
    }
    
    listener "tcp" {
      address     = "0.0.0.0:8200"
      tls_disable = 0
      tls_cert_file = "/etc/ssl/certs/pi-vault.pem"
      tls_key_file = "/etc/vault.d/pi-vault.key"
    }
    
    ui = true
    
  5. Add your CA (if you have one) to /etc/ssl/certs and run update-ca-certificates

  6. Create a vault storage location

    mkdir -p /vault/data
    chown --recursive vault:vault /vault/data/
    
  7. Allow vault to use mlock syscall to prevent memory from being swapped

    setcap cap_ipc_lock=+ep /usr/local/bin/vault
    
  8. Create a systemd process

    touch /etc/systemd/system/vault.service
    
  9. Add the following

    [Unit]
    Description="HashiCorp Vault - A tool for managing secrets"
    Documentation=https://www.vaultproject.io/docs/
    Requires=network-online.target
    After=network-online.target
    ConditionFileNotEmpty=/etc/vault.d/vault.hcl
    StartLimitIntervalSec=60
    StartLimitBurst=3
    
    [Service]
    User=vault
    Group=vault
    ProtectSystem=full
    ProtectHome=read-only
    PrivateTmp=yes
    PrivateDevices=yes
    SecureBits=keep-caps
    AmbientCapabilities=CAP_IPC_LOCK
    Capabilities=CAP_IPC_LOCK+ep
    CapabilityBoundingSet=CAP_SYSLOG CAP_IPC_LOCK
    NoNewPrivileges=yes
    ExecStart=/usr/local/bin/vault server -config=/etc/vault.d/vault.hcl
    ExecReload=/bin/kill --signal HUP $MAINPID
    KillMode=process
    KillSignal=SIGINT
    Restart=on-failure
    RestartSec=5
    TimeoutStopSec=30
    StartLimitInterval=60
    StartLimitIntervalSec=60
    StartLimitBurst=3
    LimitNOFILE=65536
    LimitMEMLOCK=infinity
    
    [Install]
    WantedBy=multi-user.target
    EOF
    
  10. Start the service with systemctl start vault

  11. Run vault operator init on the server to generate keys

  12. Unseal the vault

  13. Add the following backup job to /etc/crontab

    0  0    * * *   root    tar czvf /vault/backups/$(date +\%y-\%m-\%d-\%H-\%M)-pivault.tar.gz /vault/data
    0  0    * * *   root    find /vault/backups/* -mtime +7 -exec rm {} +
    

Install (Standalone)

kubectl apply -f k8s/certificate.yaml

helm repo add hashicorp https://helm.releases.hashicorp.com
helm search repo hashicorp/vault
helm upgrade --install vault hashicorp/vault --values helm/values.yaml

mkdir ~/.vault-keys
kubectl exec -ti vault-0 -- vault operator init -key-shares=5 -key-threshold=3 -format=json > ~/.vault-keys/cluster-keys.json
kubectl exec -ti vault-0 -- vault operator unseal

Install (Cluster)

This assumes you have an unseal vault available! See ha-test for manual unseal.

kubectl apply -f k8s/certificate.yaml

helm repo add hashicorp https://helm.releases.hashicorp.com
helm search repo hashicorp/vault
helm upgrade --install vault hashicorp/vault --values helm/ha.yaml

mkdir ~/.vault-keys
kubectl exec -ti vault-0 -- vault operator init -format=json > ~/.vault-keys/vault-cluster-keys.json
# Only run the unseal if not autounsealing
# kubectl exec -ti vault-0 -- vault operator unseal

kubectl exec -ti vault-1 -- vault operator raft join http://vault-0.vault-internal:8200
# kubectl exec -ti vault-1 -- vault operator unseal

kubectl exec -ti vault-2 -- vault operator raft join http://vault-0.vault-internal:8200
# kubectl exec -ti vault-2 -- vault operator unseal

Add/Update policy

vault policy write ducoterra policies/ducoterra.hcl

Add user

vault auth enable userpass
vault auth tune -default-lease-ttl=24h userpass
vault write auth/userpass/users/ducoterra \
    policies=ducoterra \
    password='<password>'

Enable KV Secrets

vault secrets enable -path=secret kv-v2

vault kv put secret/okta username='static-user' password='static-password'
vault kv get secret/okta

TOTP

vault secrets enable totp

vault write totp/keys/okta \
    url='otpauth://totp/Vault:reese.wells@nimbisservices.com?secret=SECRET&issuer=Okta'

vault read totp/code/okta

Policy:

path "totp/keys/*" {
    capabilities = ["update"]
}

path "totp/code/*" {
    capabilities = ["read"] 
}

Kubernetes Secrets

kubectl exec -it vault-0 -- /bin/sh

vault login -method=token <token>
vault auth enable kubernetes

vault write auth/kubernetes/config \
    token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
    kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" \
    kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt

vault policy write internal-app - <<EOF
path "internal/data/database/config" {
  capabilities = ["read"]
}
EOF

vault write auth/kubernetes/role/internal-app \
    bound_service_account_names=internal-app \
    bound_service_account_namespaces=gitlab \
    policies=internal-app \
    ttl=24h

rm /home/vault/.vault-token

Set your kube config to the namespace you want to use vault with

kubectl apply -f k8s/service-account-internal-app.yaml

Add secrets to your pod

spec:
  template:
    metadata:
      annotations:
        vault.hashicorp.com/agent-inject: "true"
        vault.hashicorp.com/role: "internal-app"
        vault.hashicorp.com/agent-inject-secret-database-config.txt: "internal/data/database/config"

Gitlab Integration

Enable JWT auth for Gitlab

# Enable jwt auth
vault auth enable jwt

# Create a policy
vault policy write myproject-production - <<EOF
# Policy name: myproject-production
#
# Read-only permission on 'secret/data/myproject/production/*' path
path "secret/data/myproject/production/*" {
  capabilities = [ "read" ]
}
EOF

# Create a role
vault write auth/jwt/role/myproject-production - <<EOF
{
  "role_type": "jwt",
  "policies": ["myproject-production"],
  "token_explicit_max_ttl": 60,
  "user_claim": "user_email",
  "bound_claims_type": "glob",
  "bound_claims": {
    "project_id": "127",
    "ref_protected": "false",
    "ref_type": "branch",
    "ref": "main"
  }
}
EOF

# Write the auth method
vault write auth/jwt/config \
    jwks_url="https://gitlab.ducoterra.net/-/jwks" \
    bound_issuer="gitlab.ducoterra.net"

Pipeline syntax

read_secrets:
  script:
    # Check job's ref name
    - echo $CI_COMMIT_REF_NAME
    # and is this ref protected
    - echo $CI_COMMIT_REF_PROTECTED
    # Vault's address can be provided here or as CI/CD variable
    - export VAULT_ADDR=https://vault.ducoterra.net
    # Authenticate and get token. Token expiry time and other properties can be configured
    # when configuring JWT Auth - https://www.vaultproject.io/api/auth/jwt#parameters-1
    - export VAULT_TOKEN="$(vault write -field=token auth/jwt/login role=myproject-production jwt=$CI_JOB_JWT)"
    # Now use the VAULT_TOKEN to read the secret and store it in environment variable
    - export PASSWORD="$(vault kv get -field=password secret/myproject/production/db)"
    # Use the secret
    - echo $PASSWORD

Certificate Management

https://learn.hashicorp.com/tutorials/vault/pki-engine https://learn.hashicorp.com/tutorials/vault/kubernetes-cert-manager

Create a CA

export ROOT_PATH=dnet

# Note: 19800h is Apple's limit
vault secrets enable -path=$ROOT_PATH pki
vault secrets tune -max-lease-ttl=19800h $ROOT_PATH

# Create a root CA
vault write $ROOT_PATH/root/generate/internal \
    common_name="Ducoterra Root CA" \
    ttl=19800h

# Create a CA URL
vault write $ROOT_PATH/config/urls \
    issuing_certificates="https://vault.ducoterra.net/v1/$ROOT_PATH/ca" \
    crl_distribution_points="https://vault.ducoterra.net/v1/$ROOT_PATH/crl"

Navigate to https://vault.ducoterra.net/v1/$ROOT_PATH/ca and download the CA. Import to your devices.

Create an intermediate CA

export ROOT_PATH=dnet
export PKI_PATH=dnet_inter

vault secrets enable -path=$PKI_PATH pki
vault secrets tune -max-lease-ttl=9900h $PKI_PATH

# Create CSR to sign with root CA
vault write -format=json $PKI_PATH/intermediate/generate/internal \
    common_name="Ducoterra Intermediate CA" \
    | jq -r '.data.csr' > certs/$PKI_PATH.csr

# Sign the CSR with the root CA
vault write -format=json $ROOT_PATH/root/sign-intermediate \
    csr=@certs/$PKI_PATH.csr format=pem_bundle ttl=9900h \
    | jq -r '.data.certificate' > certs/$PKI_PATH.cert.pem

# Save the signed cert to vault
vault write $PKI_PATH/intermediate/set-signed certificate=@certs/$PKI_PATH.cert.pem

# Create a CA URL
vault write $PKI_PATH/config/urls \
    issuing_certificates="https://vault.ducoterra.net/v1/$PKI_PATH/ca" \
    crl_distribution_points="https://vault.ducoterra.net/v1/$PKI_PATH/crl"

Navigate to https://vault.ducoterra.net/v1/$PKI_PATH/ca and download the CA. Import to your devices.

Allow .dnet and .hole certificates

export PKI_PATH=dnet_inter

# Allow .dnet subdomain
vault write $PKI_PATH/roles/dnet \
    allowed_domains=dnet \
    allow_subdomains=true max_ttl=8760h

# Allow .hole subdomain
vault write $PKI_PATH/roles/pi_hole \
    allowed_domains=hole \
    allow_subdomains=true max_ttl=8760h

Issue a certificate

export PKI_PATH=dnet # or dnet_inter
export CNAME=freenas.dnet

# Use -format=json to dump a json file
vault write $PKI_PATH/issue/dnet \
    common_name=$CNAME \
    ttl=8760h > certs/$CNAME.cert

# Pihole Example
vault write $PKI_PATH/issue/pi_hole \
    common_name=$CNAME \
    ttl=8760h > certs/$CNAME.cert

Adding cert to freenas

Only caveat here is to paste the certificate and then the full chain cert below in the "certificate" section. iOS will infintely refresh the page if the full chain isn't provided.

Adding cert to pihole

# Install lighttpd-mod-openssl
apt install -y lighttpd-mod-openssl

# Paste the isser CA in here:
vim /etc/ssl/certs/vault-ca.pem
chown www-data /etc/ssl/certs/vault-ca.pem
chmod 770 /etc/ssl/certs/vault-ca.pem

# Paste the private key first, then the certificate in here:
vim /etc/ssl/certs/pihole.pem
chown www-data /etc/ssl/certs/pihole.pem
chmod 770 /etc/ssl/certs/pihole.pem

# Add the config below to /etc/lighttpd/external.conf
vim /etc/lighttpd/external.conf
$HTTP["host"] == "pi.hole" {
  # Ensure the Pi-hole Block Page knows that this is not a blocked domain
  setenv.add-environment = ("fqdn" => "true")

  # Enable the SSL engine with a LE cert, only for this specific host
  $SERVER["socket"] == ":443" {
    ssl.engine = "enable"
    ssl.pemfile = "/etc/ssl/certs/pihole.pem"
    ssl.ca-file =  "/etc/ssl/certs/vault-ca.pem"
    ssl.honor-cipher-order = "enable"
    ssl.cipher-list = "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"
    ssl.use-sslv2 = "disable"
    ssl.use-sslv3 = "disable"       
  }

  # Redirect HTTP to HTTPS
  $HTTP["scheme"] == "http" {
    $HTTP["host"] =~ ".*" {
      url.redirect = (".*" => "https://%0$0")
    }
  }
}
# Restart the service
service lighttpd restart

Adding cert to vault

# Paste the primary cert and then the issuer CA in here:
vim /etc/ssl/certs/vault-cert.pem
chown vault:vault /etc/ssl/certs/vault-cert.pem
chmod 770 /etc/ssl/certs/vault-cert.pem

# Paste the private key in here:
vim /etc/ssl/certs/vault-key.pem
chown vault:vault /etc/ssl/certs/vault-key.pem
chmod 770 /etc/ssl/certs/vault-key.pem

Edit /etc/vault.d/vault.hcl and add the following:

listener "tcp" {
  address       = "0.0.0.0:8200"
  tls_disable   = 0
  tls_cert_file = "/etc/ssl/certs/vault-cert.pem"
  tls_key_file  = "/etc/ssl/certs/vault-key.pem"
}

Run service vault restart

Adding cert to cloudkey

THIS DOESN'T WORK

service unifi stop

# Remove the UNIFI_SSL_KEYSTORE=/etc/ssl/private/unifi.keystore.jks line from config
cp /etc/default/unifi /etc/default/unifi.back
vim /etc/default/unifi

# Remove the keystore reference
mv /usr/lib/unifi/data/keystore /usr/lib/unifi/data/keystore.back

# Copy your primary SSL Certificate into /etc/ssl/private/cloudkey.crt
cp /etc/ssl/private/cloudkey.crt /etc/ssl/private/cloudkey.crt.back
vim /etc/ssl/private/cloudkey.crt

# Copy your private key into /etc/ssl/private/cloudkey.key
cp /etc/ssl/private/cloudkey.key /etc/ssl/private/cloudkey.key.back
vim /etc/ssl/private/cloudkey.key

# Add the CA to /etc/ssl/private/vault-ca.pem
vim /etc/ssl/private/vault-ca.pem

# Generate the key bundle
openssl pkcs12 -export -in /etc/ssl/private/cloudkey.crt -inkey \
/etc/ssl/private/cloudkey.key -out /etc/ssl/private/cloudkey.p12 \
-name unifi -CAfile /etc/ssl/private/vault-ca.pem -caname vault -password pass:temppass

# Import to keystore
# Default password is "aircontrolenterprise"
keytool -importkeystore -deststorepass aircontrolenterprise \
-destkeypass aircontrolenterprise -destkeystore /usr/lib/unifi/data/keystore \
-srckeystore /etc/ssl/private/cloudkey.p12 -srcstoretype PKCS12 -srcstorepass temppass -alias unifi -noprompt

service unifi start

Revoke a certificate

export PKI_PATH=dnet_inter

vault write $PKI_PATH/revoke serial_number=<serial_number>
vault write $PKI_PATH/tidy tidy_cert_store=true tidy_revoked_certs=true

Use with cert-manager

export PKI_PATH=dnet_inter

vault policy write $PKI_PATH - <<EOF
path "$PKI_PATH*"                        { capabilities = ["read", "list"] }
path "$PKI_PATH/roles/*"   { capabilities = ["create", "update"] }
path "$PKI_PATH/sign/*"    { capabilities = ["create", "update"] }
path "$PKI_PATH/issue/*"   { capabilities = ["create"] }
EOF

vault write auth/kubernetes/role/issuer \
    bound_service_account_names=issuer \
    bound_service_account_namespaces=cert-manager \
    policies=$PKI_PATH \
    ttl=20m

kubectl -n cert-manager create serviceaccount issuer
ISSUER_SECRET_REF=$(kubectl -n cert-manager get serviceaccount issuer -o json | jq -r ".secrets[].name")

kubectl -n cert-manager apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: vault-issuer
spec:
  vault:
    server: https://vault.ducoterra.net
    path: $PKI_PATH/sign/dnet
    auth:
      kubernetes:
        mountPath: /v1/auth/kubernetes
        role: issuer
        secretRef:
          name: $ISSUER_SECRET_REF
          key: token
EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    # cert-manager.io/cluster-issuer: letsencrypt-prod
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/proxy-body-size: "0"
    nginx.org/client-max-body-size: "0"
  name: {{ .Release.Name }}
spec:
  rules:
  - host: test.dnet
    http:
      paths:
      - backend:
          service:
            name: {{ .Release.Name }}
            port:
              number: 80
        path: /
        pathType: Prefix
  tls:
  - hosts:
    - test-dnet
    secretName: test-dnet-cert
---
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
  name: test-dnet
spec:
  secretName: test-dnet-cert
  issuerRef:
    name: vault-issuer
    kind: ClusterIssuer
  commonName: test.dnet
  dnsNames:
  - test.dnet

Kubernetes External Vault Auth

https://learn.hashicorp.com/tutorials/vault/kubernetes-external-vault?in=vault/kubernetes

Connect to external vault

# On the new server (pikube - vault)
helm install vault hashicorp/vault \
    --set "injector.externalVaultAddr=https://vault.ducoterra.net"

VAULT_HELM_SECRET_NAME=$(kubectl get secrets --output=json | jq -r '.items[].metadata | select(.name|startswith("vault-token-")).name')
TOKEN_REVIEW_JWT=$(kubectl get secret $VAULT_HELM_SECRET_NAME --output='go-template={{ .data.token }}' | base64 --decode)
KUBE_CA_CERT=$(kubectl config view --raw --minify --flatten --output='jsonpath={.clusters[].cluster.certificate-authority-data}' | base64 --decode)
KUBE_HOST="https://3.14.3.104:6443"
# On the existing vault server

export PKI_PATH=dnet_inter
vault auth enable -path=pikube kubernetes

vault write auth/pikube/config \
    token_reviewer_jwt="$TOKEN_REVIEW_JWT" \
    kubernetes_host="https://3.14.3.104:6443" \
    kubernetes_ca_cert="$KUBE_CA_CERT"

vault write auth/pikube/role/issuer \
    bound_service_account_names=issuer \
    bound_service_account_namespaces=cert-manager \
    policies=$PKI_PATH \
    ttl=20m

Install cert-manager

kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.3.1/cert-manager.yaml
kubectl -n cert-manager create serviceaccount issuer
export ISSUER_SECRET_REF=$(kubectl -n cert-manager get serviceaccount issuer -o json | jq -r ".secrets[].name")
export PKI_PATH=dnet_inter

kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: vault-issuer
spec:
  vault:
    server: https://vault.ducoterra.net
    path: $PKI_PATH/sign/dnet
    auth:
      kubernetes:
        mountPath: /v1/auth/pikube
        role: issuer
        secretRef:
          name: $ISSUER_SECRET_REF
          key: token
EOF

Auto-unseal

https://learn.hashicorp.com/tutorials/vault/autounseal-transit

Enable transit on vault that will do the unsealing

# Up the token ttl to 10 years (defaults to 32 days)
vault write sys/auth/token/tune max_lease_ttl=87600h

vault secrets enable transit
vault write -f transit/keys/autounseal

tee policies/autounseal.hcl <<EOF
path "transit/encrypt/autounseal" {
   capabilities = [ "update" ]
}

path "transit/decrypt/autounseal" {
   capabilities = [ "update" ]
}
EOF

vault policy write autounseal policies/autounseal.hcl

vault token create -policy="autounseal" -wrap-ttl=120 -ttl=87600h
VAULT_TOKEN="wrapping token" vault unwrap

Enable auto unseal with kube cluster

Create a test vault in a new namespace

kubectl apply -f k8s/certificate.yaml

# Get token from above output
kubectl create secret generic auto-unseal-token --from-literal=VAULT_TOKEN="token from output"
helm upgrade --install vault hashicorp/vault --values helm/ha.yaml

Test Auto Unseal

kubectl exec -it vault-0 -- vault operator init
kubectl exec -ti vault-1 -- vault operator raft join http://vault-0.vault-internal:8200
kubectl exec -ti vault-2 -- vault operator raft join http://vault-0.vault-internal:8200

SSH

Client key signing

Enable secrets engine and generate a key

vault secrets enable -path=ssh-client-signer ssh
vault write ssh-client-signer/config/ca generate_signing_key=true

To enable port-forwarding you'll need to update the parameters:

{
  "permit-port-forwarding": ""
  "permit-pty"
}

Retrieve the public CA (and add it to your /etc/ssh/trusted-user-ca-keys.pem) with

curl -o /etc/ssh/trusted-user-ca-keys.pem https://vault.ducoterra.net/v1/ssh-client-signer/public_key

Add it to your sshd_config

echo "TrustedUserCAKeys /etc/ssh/trusted-user-ca-keys.pem" >> /etc/ssh/sshd_config

Restart the SSH service

service ssh restart

Add signing role

vault write ssh-client-signer/roles/ducoterra -<<"EOH"
{
    "allow_user_certificates": true,
    "allowed_users": "ducoterra",
    "allowed_extensions": "permit-pty,permit-port-forwarding",
    "default_extensions": [
        { "permit-pty": "" }
    ],
    "algorithm_signer": "rsa-sha2-512",
    "key_type": "ca",
    "default_user": "ducoterra",
    "ttl": "30m0s"
}
EOH
vault write ssh-client-signer/roles/pi -<<"EOH"
{
    "allow_user_certificates": true,
    "allowed_users": "pi",
    "allowed_extensions": "permit-pty,permit-port-forwarding",
    "default_extensions": [
        { "permit-pty": "" }
    ],
    "algorithm_signer": "rsa-sha2-512",
    "key_type": "ca",
    "default_user": "pi",
    "ttl": "30m0s"
}
EOH
vault write ssh-client-signer/roles/rancher -<<"EOH"
{
    "allow_user_certificates": true,
    "allowed_users": "rancher",
    "allowed_extensions": "permit-pty,permit-port-forwarding",
    "default_extensions": [
        { "permit-pty": "" }
    ],
    "algorithm_signer": "rsa-sha2-512",
    "key_type": "ca",
    "default_user": "rancher",
    "ttl": "30m0s"
}
EOH

Sign a key

export SSHUSER=pi; vault write -field=signed_key ssh-client-signer/sign/$SSHUSER public_key=@$HOME/.ssh/id_rsa.pub > ~/.ssh/id_rsa-cert.pub

SSH using the signed key

# If you saved the signed pub as key_name"-cert.pub" then you don't need to specify the signed-cert.pub part.
ssh -i signed-cert.pub -i ~/.ssh/test_rsa client

# without the cert (using default client)
ssh -i ~/.ssh/test_rsa client

Server Host Signing

Enable secrets engine

vault secrets enable -path=ssh-host-signer ssh

Generate keys:

vault write ssh-host-signer/config/ca generate_signing_key=true

Extend host key's TTL

vault secrets tune -max-lease-ttl=87600h ssh-host-signer

Create host role

vault write ssh-host-signer/roles/hostrole \
    key_type=ca \
    ttl=87600h \
    allow_host_certificates=true \
    allowed_domains="localdomains,dnet,hole,ducoterra.net" \
    allow_subdomains=true

Sign the host's public key

vault write ssh-host-signer/sign/hostrole \
    cert_type=host \
    public_key=@$HOME/.ssh/id_rsa.pub

Write the signed certificate to the ssh config on the host

vault write -field=signed_key ssh-host-signer/sign/hostrole \
    cert_type=host \
    public_key=@$HOME/.ssh/id_rsa.pub > /etc/ssh/ssh_host_rsa_key-cert.pub

Assign correct permissions

chmod 0640 /etc/ssh/ssh_host_rsa_key-cert.pub

Add to sshd_config

echo HostKey /etc/ssh/ssh_host_rsa_key >> /etc/ssh/sshd_config
echo HostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub >> /etc/ssh/sshd_config

Restart the ssh service

service ssh restart

Add certificate to client

echo '@cert-authority *.ducoterra.net '$(vault read -field=public_key ssh-host-signer/config/ca) >> ~/.ssh/known_hosts

AWS

Credential Management

https://www.vaultproject.io/docs/secrets/aws

Enable AWS secrets

vault secrets enable aws
vault secrets tune -default-lease-ttl=24h aws

Allow user to access AWS path

path "aws/*" {
    capabilities = ["create", "read", "update", "delete", "list"]
}

Create a vault-secret user

# Generate a vault-root-user
export VAULT_ROOT_USER_ARN=$(aws iam create-user --user-name vault-root-user | jq -r '.User.Arn')

# Create a root user policy template with the user arn
export ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
export VAULT_PUPPET_ARNS='arn:aws:iam::'$ACCOUNT_ID':user/vault-*'
jq -r ".Statement[].Resource[0] = \"$VAULT_PUPPET_ARNS\"" < aws/vault_root_policy.json > /tmp/vault_root_policy.json
# Create the vault root user policy from the template
export VAULT_ROOT_USER_POLICY_ARN=$(aws iam create-policy --policy-name vault-root-policy --policy-document file:///tmp/vault_root_policy.json | jq -r '.Policy.Arn')
# Attach the vault root user policy
aws iam attach-user-policy --user-name vault-root-user --policy-arn $VAULT_ROOT_USER_POLICY_ARN

# Create the key rotation policy
jq -r ".Statement[].Resource[0] = \"$VAULT_ROOT_USER_ARN\"" < aws/vault_root_rotate_policy.json > /tmp/vault_root_rotate_policy.json
export VAULT_ROOT_USER_ROTATE_POLICY_ARN=$(aws iam create-policy --policy-name vault-root-rotate-policy --policy-document file:///tmp/vault_root_rotate_policy.json | jq -r '.Policy.Arn')
# Attach the key rotation policy
aws iam attach-user-policy --user-name vault-root-user --policy-arn $VAULT_ROOT_USER_ROTATE_POLICY_ARN

# Create access keys for the vault-root-user
export $(aws iam create-access-key --user-name vault-root-user | jq -r '"VAULT_ROOT_ACCESS_KEY_ID=\(.AccessKey.AccessKeyId) VAULT_ROOT_SECRET_ACCESS_KEY=\(.AccessKey.SecretAccessKey)"')

Write aws root config with access key and secret key from above

vault write aws/config/root \
    access_key=$VAULT_ROOT_ACCESS_KEY_ID \
    secret_key=$VAULT_ROOT_SECRET_ACCESS_KEY \
    region=us-east-2

Rotate your credentials

vault write -f aws/config/rotate-root

Creating IAM Users

Create a terraform-user role

vault write aws/roles/terraform-user \
    credential_type=iam_user \
    policy_document=@aws/terraform_policy.json

Read credentials

vault read aws/creds/terraform-user

Automate credentials generation (https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html)

export $(vault read -format json aws/creds/terraform-user | jq -r '"AWS_ACCESS_KEY_ID=\(.data.access_key) AWS_SECRET_ACCESS_KEY=\(.data.secret_key)"')
export AWS_DEFAULT_REGION=us-east-2
export AWS_PROFILE=default
aws configure set region $AWS_DEFAULT_REGION --profile default
aws configure set aws_access_key_id $AWS_ACCESS_KEY_ID --profile default
aws configure set aws_secret_access_key $AWS_SECRET_ACCESS_KEY --profile default

STS Tokens

To create STS federated tokens use the following permissions:

{
  "Version": "2012-10-17",
  "Statement": {
    "Effect": "Allow",
    "Action": [
      "sts:GetFederationToken"
    ],
    "Resource": "*"
  }
}

Create a role with the example policy

vault write aws/roles/ec2_admin \
    credential_type=federation_token \
    policy_document=@aws/ec2_admin.json

Generate a role with a ttl of 60 minutes

vault write aws/sts/ec2_admin ttl=24h

Authentication

Create a vault aws policy

vault policy write aws_wireguard policies/aws_wireguard.hcl

Create a vault-auth user

# Generate a vault-auth-user
export VAULT_AUTH_USER_ARN=$(aws iam create-user --user-name vault-auth-user | jq -r '.User.Arn')

# Create an auth user policy template with the user arn
export ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
# Create the vault auth user policy from the template
export VAULT_AUTH_USER_POLICY_ARN=$(aws iam create-policy --policy-name vault-auth-policy --policy-document file://aws/vault_auth_policy.json | jq -r '.Policy.Arn')
# Attach the vault root user policy
aws iam attach-user-policy --user-name vault-auth-user --policy-arn $VAULT_AUTH_USER_POLICY_ARN

# Generate credentials
export $(aws iam create-access-key --user-name vault-auth-user | jq -r '"VAULT_AUTH_ACCESS_KEY_ID=\(.AccessKey.AccessKeyId) VAULT_AUTH_SECRET_ACCESS_KEY=\(.AccessKey.SecretAccessKey)"')
# Write credentials to vault
vault write auth/aws/config/client secret_key=$VAULT_AUTH_SECRET_ACCESS_KEY access_key=$VAULT_AUTH_ACCESS_KEY_ID

Create a vault-auth role

# Create the role
exort VAULT_AUTH_ROLE_ARN=$(aws iam create-role --role-name vault-auth-role --assume-role-policy-document file://aws/vault_auth_trust_policy.json | jq -r '.Role.Arn')

Create the vault role with the role arn

vault write auth/aws/role/aws-wireguard auth_type=iam bound_iam_principal_arn=$VAULT_AUTH_ROLE_ARN policies=aws_wireguard max_ttl=30m
vault write auth/aws/config/client iam_server_id_header_value=vault.ducoterra.net

Login on the ec2 instance

vault login -method=aws header_value=vault.ducoterra.net role=aws-wireguard