[!NOTE|label:references]

environment

install

  • macos

    $ brew tap hashicorp/tap
    $ brew install hashicorp/tap/vault
    
  • ubunut/debian

    $ wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
    $ echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
    $ sudo apt update && sudo apt install vault
    
  • centos/rhel

    $ sudo yum install -y yum-utils
    $ sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
    $ sudo yum -y install vault
    

completion

$ vault -autocomplete-install

status

$ vault status
Key             Value
---             -----
Seal Type       shamir
Initialized     true
Sealed          false
Total Shares    5
Threshold       3
Version         1.9.0
Build Date      n/a
Storage Type    file
Cluster Name    vault-cluster-ea2f5821
Cluster ID      e034c5c3-53c6-2d38-2adf-e9bbd57ad87c
HA Enabled      false

get info

auth

  • list role type

    $ vault auth list
    Path        Type       Accessor                 Description                Version
    ----        ----       --------                 -----------                -------
    approle/    approle    auth_approle_375212fa    n/a                        n/a
    ldap/       ldap       auth_ldap_8fc0eb82       n/a                        n/a
    token/      token      auth_token_f61ed5a6      token based credentials    n/a
    
  • list roles

    $ vault list auth/approle/role
    Keys
    ----
    jenkins
    jenkins-role
    
  • read role

    $ vault read auth/approle/role/jenkins
    Key                        Value
    ---                        -----
    bind_secret_id             true
    local_secret_ids           false
    secret_id_bound_cidrs      <nil>
    secret_id_num_uses         0
    secret_id_ttl              0s
    token_bound_cidrs          []
    token_explicit_max_ttl     0s
    token_max_ttl              4h
    token_no_default_policy    false
    token_num_uses             0
    token_period               0s
    token_policies             [service-ssh]
    token_ttl                  1h
    token_type                 default
    

security

  • get token

    $ vault auth list
    Path        Type       Accessor                 Description                Version
    ----        ----       --------                 -----------                -------
    approle/    approle    auth_approle_375212fa    n/a                        n/a
    ldap/       ldap       auth_ldap_8fc0eb82       n/a                        n/a
    token/      token      auth_token_f61ed5a6      token based credentials    n/a
    
    $ vault token lookup
    Key                 Value
    ---                 -----
    accessor            Wf********************5y
    creation_time       1640161759
    creation_ttl        0s
    display_name        root
    entity_id           n/a
    expire_time         <nil>
    explicit_max_ttl    0s
    id                  s.s**********************K
    meta                <nil>
    num_uses            0
    orphan              true
    path                auth/token/root
    policies            [root]
    ttl                 0s
    type                service
    

list

  • list all path

    $ vault secrets list [ -detailed ]
    Path                       Type         Accessor              Description
    ----                       ----         --------              -----------
    devops/                    kv           kv_374198a0           for devops
    
  • list keys

    $ vault kv list devops/service-account/
    Keys
    ----
    read-only
    read-write
    read-write-delete
    
  • get contents

    $ vault kv get devops/service-account/read-only
    =============== Secret Path ===============
    devops/data/service-account/read-only
    
    ======= Metadata =======
    Key                Value
    ---                -----
    created_time       2023-03-06T15:52:45.827580966Z
    custom_metadata    <nil>
    deletion_time      n/a
    destroyed          false
    version            5
    
    ============ Data ============
    Key                      Value
    ---                      -----
    cn                       read-only
    dn                       CN=read-only,OU=Service-Accounts,DC=example,DC=com
    password                 ********
    sAMAccountName           read-only
    username                 read-only
    

policy

# list all policies
$ vault policy list
# read default policy
$ vault policy read default

approle

[!NOTE|label:references:]

via CLI

  • pre-setup

    $ export VAULT_ADDR='https://vault.domain.com'
    $ export VAULT_TOKEN='s.s**********************K'
    
    # VAULT_TOKEN=$(vault print token)
    
  • list

    $ vault list auth/approle/role
    Keys
    ----
    jenkins
    jenkins-role
    ...
    
    # or
    $ curl -s --header "X-Vault-Token: $VAULT_TOKEN" \
              --request LIST "$VAULT_ADDR/v1/auth/approle/role" |
      jq -r .data.keys[]
    jenkins
    jenkins-role
    
  • setup

    $ vault write auth/approle/role/devops \
                  token_num_uses=0 \
                  secret_id_num_uses=0 \
                  policies="devops"
    Success! Data written to: auth/approle/role/devops
    
    $ vault read auth/approle/role/devops
    Key                        Value
    ---                        -----
    bind_secret_id             true
    local_secret_ids           false
    policies                   [devops]
    secret_id_bound_cidrs      <nil>
    secret_id_num_uses         0
    secret_id_ttl              0s
    token_bound_cidrs          []
    token_explicit_max_ttl     0s
    token_max_ttl              0s
    token_no_default_policy    false
    token_num_uses             0
    token_period               0s
    token_policies             [devops]
    token_ttl                  0s
    token_type                 default
    

get approle mount path

$ vault auth list -format=json | jq -r 'to_entries[] | select(.value.type=="approle") | .key'
approle/

list role-id and approle

mount="approle"
for r in $(vault list -format=json "auth/${mount}/role" | jq -r '.[]'); do
  rid=$(vault read -format=json "auth/${mount}/role/${r}/role-id" | jq -r '.data.role_id')
  echo "${rid} | ${r}"
done

get approle from role-id

mount='approle'
FOUND_ROLE=''
for r in $(vault list -format=json "auth/${mount}/role" | jq -r '.[]'); do
  rid=$(vault read -format=json "auth/${mount}/role/${r}/role-id" | jq -r '.data.role_id')
  if [[ "${rid}" == "${ROLE_ID}" ]]; then
    FOUND_ROLE="${r}"
    break
  fi
done

get policies from role

$ vault read -format=json "auth/approle/role/${ROLE_NAME}" |
        jq -r '.data.token_policies // .data.policies'

via API

# enable auth method
$ curl \
      --header "X-Vault-Token: ..." \
      --request POST \
      --data '{"type": "approle"}' \
      http://vault.domain.com:8200/v1/sys/auth/approle

# create approle with policy
$ curl \
      --header "X-Vault-Token: ..." \
      --request POST \
      --data '{"policies": "dev-policy,test-policy"}' \
      http://vault.domain.com:8200/v1/auth/approle/role/ROLE_NAME

# check identifier of role
$ curl \
      --header "X-Vault-Token: ..." \
      http://vault.domain.com:8200/v1/auth/approle/role/ROLE_NAME/role-id
{
  "data": {
    "role_id": "988a9dfd-ea69-4a53-6cb6-9d6b86474bba"
  }
}

# create new security
$ curl \
      --header "X-Vault-Token: ..." \
      --request POST \
       http://vault.domain.com:8200/v1/auth/approle/role/ROLE_NAME/secret-id
{
  "data": {
    "secret_id_accessor": "45946873-1d96-a9d4-678c-9229f74386a5",
    "secret_id": "37b74931-c4cd-d49a-9246-ccc62d682a25",
    "secret_id_ttl": 600,
    "secret_id_num_uses": 40
  }
}

get secret_id and role_id

# read for role-id
$ vault read auth/approle/role/devops/role-id
Key        Value
---        -----
role_id    1*******-****-****-****-***********5

# re-generate secret_id
$ vault write -f auth/approle/role/devops/secret-id
Key                   Value
---                   -----
secret_id             3*******-****-****-****-***********3
secret_id_accessor    9*******-****-****-****-***********b
secret_id_ttl         0

# list for secret_id
$ vault list auth/approle/role/devops/secret-id
Keys
-----
9*******-****-****-****-***********b

operator

tokens

[!NOTE|label:references:]

TOKEN TYPE VAULT 1.9.X + VAULT 1.10 -
Service tokens s.<random> hvs.<random>
Batch tokens b.<random> hvb.<random>
Recovery tokens r.<random> hvr.<random>

root tokens

[!TIP]

  • initial root token with no expiration

    $ vault operator init
    
  • generate root token with share holders ( with unseal key )

    [!NOTE|label:references:]

    $ vault operator generate-root
    
    • example:

      • generate an otp code for the final token

        $ vault operator generate-root -generate-otp
        
      • start a root token generation:

        $ vault operator generate-root -init
        
      • enter an unseal key to progress root token generation:

        $ vault operator generate-root
        
  • check status

    $ vault operator generate-root -status
    Nonce         n/a
    Started       false
    Progress      0/3
    Complete      false
    OTP Length    26
    

init

$ vault operator init
Unseal Key 1: p******************************************Y
Unseal Key 2: /******************************************y
Unseal Key 3: j******************************************I
Unseal Key 4: V******************************************K
Unseal Key 5: l******************************************M

Initial Root Token: s.s**********************K
  • check status

    $ vault operator key-status
    Key Term            1
    Install Time        22 Dec 21 08:29 UTC
    Encryption Count    211817
    
  • generate new unseal key

    $ vault operator rekey
    
  • seal/unseal

    $ vault operator seal
    $ vault operator unseal
    

ssh

[!NOTE|label:references:]

- TRADITIONAL SSH VAULT SSH
Authentication static public key, long-lived dynamic certificate, with TTL
Key Management maintain authorized_keys on every server servers only trust the Vault CA
Key Compromise permanently valid until manually removed from all servers automatically expires with certificate TTL
Access Revocation must log in to every server to remove the key simply stop renewing — certificate expires automatically
Audit difficult to track who used which key complete audit log in Vault
- authorized_keys VAULT CA
Initial Setup deploy public key to every server once update sshd_config on every server once
Add User add key to every server no server changes needed
Remove User remove key from every server stop renewing — wait for certificate to expire
Employee Offboarding log in to every server to remove the key revoke Vault permission — wait for certificate to expire
Key Compromise log in to every server to remove the key stop renewing — certificate expires automatically

client key sign

PATH/ENDPOINT CAPABILITIES DESCRIPTION
ssh/roles/ list, read, write, delete managing SSH role configurations
ssh/sign/ create, update issuing certificates, not allowed to list
ssh/config/ca read, write CA Configuration
ssh/issue/ create, update issuing certificates (another method)

signing key & role configuration

[!NOTE|label:flow]

  • vault:
    1. create/enable ssh engine ( <name> )
    2. create CA signing key (private/public key pair) for ssh engine ( <name>/config/ca )
    3. create role for ssh engine ( <name>/roles/<role> )
  • remote server:
    1. download CA public key and add to all servers ( sshd_config -> TrustedUserCAKeys )
  • mount ssh secret engine

    $ vault secrets enable -path=devops-ssh ssh
    
  • configure vault with a ca

    # vault generate a new signing key ( private/public key pair )
    $ vault write devops-ssh/config/ca generate_signing_key=true
    
    # provide private/public key pairs manually
    $ vault write devops-ssh/config/ca \
            private_key="..." \
            public_key="..."
    # or
    $ vault write devops-ssh/config/ca \
            private_key=@/path/to/ca_key \
            public_key=@/path/to/ca_key.pub
    
  • add CA (public key) to all servers

    [!NOTE] the Vault CA public key is a ssh public key ( ssh-rsa xxx )

    # download pem for `PATH` - v1/PATH/public_key (API)
    $ curl -o /etc/ssh/trusted-user-ca-keys.pem http://vault.sample.com:8200/v1/PATH/public_key
    # download pem for `devops-ssh` - v1/devops-ssh/public_key (API) | devops-ssh/config/ca (CLI)
    $ vault read -field=public_key devops-ssh/config/ca > /etc/ssh/trusted-user-ca-keys.pem
    
    # modify sshd_config to `TrustedUserCAKeys`
    $ sudo vim /etc/ssh/sshd_config
    ...
    TrustedUserCAKeys /etc/ssh/trusted-user-ca-keys.pem
    
    # restart sshd
    $ sudo systemctl daemon-reload
    $ sudo systemctl restart sshd.service
    
  • create role

    # heredoc
    $ vault write devops-ssh/roles/ROLE_NAME -<<"EOH"
    {
      "algorithm_signer": "rsa-sha2-256",
      "allow_user_certificates": true,
      "allowed_users": "*",
      "allowed_extensions": "permit-pty,permit-port-forwarding",
      "default_extensions": {
        "permit-pty": ""
      },
      "key_type": "ca",
      "default_user": "ubuntu",
      "ttl": "30m0s"
    }
    EOH
    
    # cli
    $ vault write devops-ssh/roles/ROLE_NAME \
            algorithm_signer=rsa-sha2-256 \
            allow_user_certificates=true \
            allowed_users="*" \
            allowed_extensions="permit-pty,permit-port-forwarding" \
            default_extensions="permit-pty=" \
            key_type=ca \
            default_user=ubuntu \
            ttl=30m
    # sample:
    $ vault write path/to/ssh/roles/ROLE_NAME \
            allow_user_certificates=true \
            allow_host_certificates=false \
            allowed_users="*" \
            allowed_extensions="permit-pty,permit-port-forwarding" \
            default_extensions="permit-pty=,permit-port-forwarding=" \
            key_type=ca \
            default_user=neo \
            ttl=168h
    

client ssh authentication/sign ssh key with Vault CA

[!NOTE|label:process]

ssh-keygen
├──ssh public key
│     │ ( sign with vault CA )
│     ▼
│  ssh certificate ╮
│                  ├ ssh with signed certificate
└──ssh private key ╯
# create ssh-key paire
$ ssh-keygen -t ed25519 -C 'user@example.com'
# sign the public key
$ vault write PATH/sign/ROLE_NAME \
        public_key=@$HOME/.ssh/id_ed25519.pub

Key             Value
---             -----
serial_number   c73f26d2340276aa
signed_key      ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1...

# or customized
$ vault write PATH/sign/ROLE_NAME -<<"EOH"
{
  "public_key": "ssh-rsa AAA...",
  "valid_principals": "my-user",
  "key_id": "custom-prefix",
  "extensions": {
    "permit-pty": "",
    "permit-port-forwarding": ""
  }
}
EOH
# get/save the signed keys
$ vault write -field=signed_key PATH/sign/ROLE_NAME \
        public_key=@$HOME/.ssh/id_ed25519.pub > signed-cert.pub

# verify
$ ssh-keygen -Lf ~/.ssh/signed-cert.pub

# ssh
#       CertificateFile       IdentityFile
#     +----------------+ +------------------+
$ ssh -i signed-cert.pub -i ~/.ssh/id_ed25519 username@domain.com

host key sign

  • mount ssh security

    $ vault secrets enable -path=devops-ssh-hosts ssh
    Successfully mounted 'ssh' at 'devops-ssh-hosts'!
    
  • configure CA

    # generate new signing key automatically ( private/public key pair )
    $ vault write devops-ssh-hosts/config/ca generate_signing_key=true
    Key             Value
    ---             -----
    public_key      ssh-rsa AAAAB3NzaC1yc2EA...
    
    # with local key pairs
    $ vault write devops-ssh-hosts/config/ca \
            private_key="..." \
            public_key="..."
    # or with file path
    $ vault write devops-ssh-hosts/config/ca \
            private_key=@/path/to/private_key \
            public_key=@/path/to/public_key
    
  • extend host key certificate ttls

    $ vault secrets tune -max-lease-ttl=87600h devops-ssh-hosts
    
  • create role

    $ vault write devops-ssh-hosts/roles/hostrole \
            key_type=ca \
            algorithm_signer=rsa-sha2-256 \
            ttl=87600h \
            allow_host_certificates=true \
            allowed_domains="localdomain,example.com" \
            allow_subdomains=true
    
  • sign ssh public key

    $ vault write devops-ssh-hosts/sign/hostrole \
        cert_type=host \
        public_key=@/etc/ssh/ssh_host_ed25519_key.pub
    Key             Value
    ---             -----
    serial_number   3746eb17371540d9
    signed_key      ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1y...
    
  • signed certificate as HostCertificate

    $ vault write -field=signed_key devops-ssh-hosts/sign/hostrole \
        cert_type=host \
        public_key=@/etc/ssh/ssh_host_ed25519_key.pub > /etc/ssh/ssh_host_ed25519_key-cert.pub
    
    $ chmod 0640 /etc/ssh/ssh_host_ed25519_key-cert.pub
    
    # modify sshd_config
    $ sudo vim /etc/ssh/sshd_config
    ...
    # For client keys
    TrustedUserCAKeys /etc/ssh/trusted-user-ca-keys.pem
    ...
    # For host keys
    HostKey /etc/ssh/ssh_host_ed25519_key
    HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub
    
    $ sudo systemctl daemon-reload
    $ sudo systemctl restasrt sshd.service
    

verify

  • retrieve the host signing ca public key

    # API
    $ curl http://vault.domain.com:8200/v1/devops-ssh-hosts/public_key
    # CLI
    $ vault read -field=public_key devops-ssh-hosts/config/ca
    
  • add into ~/.ssh/authorized_keys

    $ cat >> ~/.ssh/known_hosts << EOF
    @cert-authority *.example.com ssh-rsa AAAAB3NzaC1yc2EAAA...
    EOF
    

troubleshooting

  • set verbose log level

    $ sudo vim /etc/ssh/sshd_config
    ...
    LogLevel VERBOSE
    
    $ sudo systemctl daemon-reload
    $ sudo systemctl restart sshd.services
    
  • check in /var/log/auth.log

    $ tail -f /var/log/auth.log | grep --line-buffered "sshd"
    

ssh secrets engine (API)

usage

API

[!NOTE|label:references:]

$ curl \
      -H "X-Vault-Token: f3b09679-3001-009d-2b80-9c306ab81aa6" \
      -H "X-Vault-Namespace: ns1/ns2/" \
      -X GET \
      http://vault.domain.com:8200/v1/secret/foo

# or
$ curl \
      -H "X-Vault-Token: f3b09679-3001-009d-2b80-9c306ab81aa6" \
      -X GET \
      http://vault.domain.com:8200/v1/ns1/ns2/secret/foo

CLI

[!NOTE|label:references:]

path-help

 $ vault path-help devops
   ...

     ^.*$

     ^config$
         Configures settings for the KV store

     ^data/(?P<path>.*)$
         Write, Patch, Read, and Delete data in the Key-Value Store.

     ^delete/(?P<path>.*)$
         Marks one or more versions as deleted in the KV store.

     ^destroy/(?P<path>.*)$
         Permanently removes one or more versions in the KV store

     ^metadata/(?P<path>.*)$
         Configures settings for the KV store

     ^undelete/(?P<path>.*)$
         Undeletes one or more versions from the KV store.
  • and more

    $ vault path-help sys/mounts
    Request:        mounts
    Matching Route: ^mounts$
    
    ## DESCRIPTION
    This path responds to the following HTTP methods.
    
        GET /
            Lists all the mounted secret backends.
    
        GET /<mount point>
            Get information about the mount at the specified path.
    
        POST /<mount point>
            Mount a new secret backend to the mount point in the URL.
    
        POST /<mount point>/tune
            Tune configuration parameters for the given mount point.
    
        DELETE /<mount point>
            Unmount the specified mount point.
    

stdin

$ echo -n '{"value":"itsasecret"}' | vault kv put secret/password -

# or
$ echo -n "itsasecret" | vault kv put secret/password value=-

Files

$ vault kv put secret/password @data.json

# or
$ vault kv put secret/password value=@data.txt

basic usage

$ export VAULT_ADDR='http://vault.domain.com:8200'
$ export VAULT_TOKEN=root

# enable azure
$ vault auth enable azure

# write config
$ vault write auth/azure/config \
              tenant_id="${TENANT_ID}" \
              client_id="${CLIENT_ID}" \
              client_secret="${CLIENT_SECRET}" \
              resource="https://management.azure.com/"

# write role
$ vault write auth/azure/role/rotation-role \
              bound_subscription_ids="${SUBSCRIPTION_ID}" \
              bound_resource_groups="${RESOURCE_GROUP_NAME}"

# login
$ vault write auth/azure/login \
              role="rotation-role" \
              jwt="${ACCESS_TOKEN_JWT}" \
              subscription_id="${SUBSCRIPTION_ID}" \
              resource_group_name="${RESOURCE_GROUP_NAME}" \
              vm_name="${VM_NAME}"
  • result
    Key                               Value
    ---                               -----
    token                             hvs.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    token_accessor                    XXXXXXXXXXXXXXXXXXXXXX
    token_duration                    768h
    token_renewable                   true
    token_policies                    ["default"]
    identity_policies                 []
    policies                          ["default"]
    token_meta_vm_name                vault-azure-tests-vm
    token_meta_resource_group_name    vault_azure_tests_XXXXXXXX
    token_meta_role                   rotation-role
    token_meta_subscription_id        XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX
    

using vault with curl

[!TIP|label:references]

CACERT=$(vault kv get -field crt my/cert/path/CACERT)
CERT=$(vault kv get -field crt my/cert/path/TESTCERT)
KEY=$(vault kv get -field key my/cert/path/TESTCERT)

curl -v \
    --cacert <(echo "$CACERT") \
    --cert <(echo "$CERT") \
    --key <(echo "$KEY") \
    --location \
    --request GET 'https://my.end.point'
Copyright © marslo 2020-2026 all right reserved,powered by GitbookLast Modified: 2026-07-08 22:47:01

results matching ""

    No results matching ""