Introduction
This article is intended to supplement the main tutorial at https://developer.hashicorp.com/vault/tutorials/enterprise/namespaces-secrets-sharing. As the tutorial utilises userpass authentication the intention of this article is to provide insight into configuring cross namespace access for additional authentication methods, as the implementation strategy can differ per authentication method.
Note the initial configuration of each individual authentication method is considered out of scope of this document.
Expected Outcome
Read content from a second namespace using a token which was created in the first namespace, with the authentication method being either:
- Kubernetes authentication
- Certificate authentication
- LDAP authentication
- OIDC authentication
The above authentication methods are not the only methods for which this process can be used, they are the methods which have been tested and confirmed to work in the context of writing this guide.
Prerequisites
- Vault Enterprise 1.13.0 or newer.
- Authentication method of choosing must be configured and operational.
- The
sys/config/group-policy-application
API endpoint must havegroup_policy_application_mode
set towithin_namespace_hierarchy
.
Use Case
The same naming schema and setup script detailed at https://developer.hashicorp.com/vault/tutorials/enterprise/namespaces-secrets-sharing#scenario-setup will be used and referenced by this guide.
The main point of difference to consider when configuring cross namespace access is the relationship of the name of the entity or group alias we create prior to authentication and the name supplied by the authentication method - these typically must match, however there can be additional configurations required to be aware of.
Procedure
Kubernetes authentication:
The main set of commands are the same when compared to the lab-setup.sh script, however we must ensure both the Kubernetes auth method role is configured with alias_name_source=serviceaccount_name
and the name of the entity alias created matches the Kubernetes namespace and service account which will be authenticating to Vault.
Implementation process:
# Create new namespaces - they are peers
vault namespace create us-west-org
vault namespace create us-east-org
#--------------------------
# us-west-org namespace
#--------------------------
VAULT_NAMESPACE=us-west-org vault auth enable kubernetes
VAULT_NAMESPACE=us-west-org vault write auth/kubernetes/config out_of=scope
VAULT_NAMESPACE=us-west-org vault write auth/kubernetes/role/cross-namespace-demo bound_service_account_names="mega-app" bound_service_account_namespaces="client-nicecorp" alias_name_source="serviceaccount_name"
# Create an entity
VAULT_NAMESPACE=us-west-org vault auth list -format=json | jq -r '.["kubernetes/"].accessor' > accessor.txt
VAULT_NAMESPACE=us-west-org vault write -format=json identity/entity name="entity-for-mega-app" | jq -r ".data.id" > entity_id.txt
VAULT_NAMESPACE=us-west-org vault write identity/entity-alias name="client-nicecorp/mega-app" canonical_id=$(cat entity_id.txt) mount_accessor=$(cat accessor.txt)
#--------------------------
# us-east-org namespace
#--------------------------
VAULT_NAMESPACE=us-east-org vault secrets enable -path="kv-marketing" kv-v2
VAULT_NAMESPACE=us-east-org vault kv put kv-marketing/campaign start_date="March 1, 2023" end_date="March 31, 2023" prise="Certification voucher" quantity="100"
# Create a policy to allow read access to kv-marketing
VAULT_NAMESPACE=us-east-org vault policy write marketing-read-only -<<EOF
path "kv-marketing/data/campaign" {
capabilities = ["read"]
}
EOF
# Create a group
VAULT_NAMESPACE=us-east-org vault write -format=json identity/group name="campaign-admin" policies="marketing-read-only" member_entity_ids=$(cat entity_id.txt)
Lines of relevance:
- When creating the Kubernetes auth method role the service account name is mega-app, in the client-nicecorp namespace.
alias_name_source
is also set toserviceaccount_name
. - When creating the entity alias the name is specified as client-nicecorp/mega-app, taking the two values previously supplied in the format of namespace/service-account-name.
Next, authenticate to Vault using the Kubernetes auth method and receive a token, for example, assuming you have a valid JWT written to jwt.txt:
VAULT_NAMESPACE=us-west-org vault write -format=json auth/kubernetes/login role=cross-namespace-demo jwt=$(cat jwt.txt) | jq -r .auth.client_token > token.txt
Last, use the token received from the us-west-org namespace to read secrets in the us-east-org namespace:
VAULT_NAMESPACE=us-east-org VAULT_TOKEN=$(cat token.txt) vault kv get kv-marketing/campaign
Certificate Authentication:
The main set of commands are the same when compared to the lab-setup.sh script, however we must ensure the value specified for allowed_dns_sans
must be used as the name when creating the entity-alias. This aligns with the Subject Alternative Name and Subject field on the client certificate. For example:
Vault role:
VAULT_NAMESPACE=us-west-org vault read -field=allowed_dns_sans auth/cert/certs/niles-peppertrout
[niles-client-auth.vault.nicecorp.org]
Client certificate:
openssl x509 -noout -in client.crt -subject -ext subjectAltName
subject=CN=niles-client-auth.vault.nicecorp.org
X509v3 Subject Alternative Name:
DNS:niles-client-auth.vault.nicecorp.org
Entity alias creation:
VAULT_NAMESPACE=us-west-org vault write identity/entity-alias name="niles-client-auth.vault.nicecorp.org" canonical_id=$(cat entity_id.txt) mount_accessor=$(cat accessor.txt)
All other configuration steps are the same.
LDAP Authentication:
LDAP differs from the previous two authentication methods in the use of identity groups instead of an identity entity.
A configuration requirement is the group alias name when created in Vault must match the LDAP group cn
attribute value, or whichever attribute is specified by the groupattr
configuration parameter on the LDAP auth method.
Implementation process:
# Create new namespaces - they are peers
vault namespace create us-west-org
vault namespace create us-east-org
#--------------------------
# us-west-org namespace
#--------------------------
VAULT_NAMESPACE=us-west-org vault auth enable ldap
VAULT_NAMESPACE=us-west-org vault write auth/ldap/config out_of=scope
# Create a group and group alias
VAULT_NAMESPACE=us-west-org vault auth list -format=json | jq -r '.["ldap/"].accessor' > accessor.txt
VAULT_NAMESPACE=us-west-org vault write -format=json identity/group name="dev-a-ldap-external-group" type="external" | jq -r ".data.id" > group-id.txt
VAULT_NAMESPACE=us-west-org vault write identity/group-alias name="dev-a" mount_accessor=$(cat accessor.txt) canonical_id=$(cat group-id.txt)
#--------------------------
# us-east-org namespace
#--------------------------
VAULT_NAMESPACE=us-east-org vault secrets enable -path="kv-marketing" kv-v2
VAULT_NAMESPACE=us-east-org vault kv put kv-marketing/campaign start_date="March 1, 2023" end_date="March 31, 2023" prise="Certification voucher" quantity="100"
# Create a policy to allow read access to kv-marketing
VAULT_NAMESPACE=us-east-org vault policy write marketing-read-only -<<EOF
path "kv-marketing/data/campaign" {
capabilities = ["read"]
}
EOF
# Create a group in the us-east-org namespace
VAULT_NAMESPACE=us-east-org vault write -format=json identity/group name="dev-a-external" policies="marketing-read-only" member_group_ids=$(cat group-id.txt)
# Authenticate to the us-west-org namespace using the LDAP credentials
VAULT_NAMESPACE=us-west-org vault login -field=token -no-store -method=ldap username=out-of-scope password="out-of-scope" > token.txt
# Read the secret in us-east-org namespace using a token issued in us-west-org namespace
VAULT_NAMESPACE=us-east-org VAULT_TOKEN=$(cat token.txt) vault kv get kv-marketing/campaign
OIDC Authentication:
OIDC Authentication will also make use of identity groups instead of an identity entity. Note that if your use case involves multiple groups needing access across namespaces you will need to create an external group in Vault (in the us-west-org namespace) for each group in your OIDC provider, then add all of the relevant group ids from the us-west-org namespace to the identity group in the us-east-org namespace. Additionally, the name specified for the group alias in Vault must match the name of the OIDC role.
Implementation process:
# Create new namespaces - they are peers
vault namespace create us-west-org
vault namespace create us-east-org
#--------------------------
# us-west-org namespace
#--------------------------
VAULT_NAMESPACE=us-west-org vault auth enable oidc
VAULT_NAMESPACE=us-west-org vault write auth/oidc/config out=of=scope
VAULT_NAMESPACE=us-west-org vault write auth/oidc/role/campaign-admin out=of=scope
# Create an entity
VAULT_NAMESPACE=us-west-org vault auth list -format=json | jq -r '.["oidc/"].accessor' > accessor.txt
VAULT_NAMESPACE=us-west-org vault write -format=json identity/group name="campaign-admin-group" type="external" | jq -r ".data.id" > group-id.txt
VAULT_NAMESPACE=us-west-org vault write identity/group-alias name="campaign-admin" mount_accessor=$(cat accessor.txt) canonical_id=$(cat group-id.txt)
#--------------------------
# us-east-org namespace
#--------------------------
VAULT_NAMESPACE=us-east-org vault secrets enable -path="kv-marketing" kv-v2
VAULT_NAMESPACE=us-east-org vault kv put kv-marketing/campaign start_date="March 1, 2023" end_date="March 31, 2023" prise="Certification voucher" quantity="100"
# Create a policy to allow read access to kv-marketing
VAULT_NAMESPACE=us-east-org vault policy write marketing-read-only -<<EOF
path "kv-marketing/data/campaign" {
capabilities = ["read"]
}
EOF
# Create a group
VAULT_NAMESPACE=us-east-org vault write -format=json identity/group name="campaign-admin" policies="marketing-read-only" member_entity_ids=$(cat group-id.txt)
# Authenticate to the us-west-org namespace using OIDC
VAULT_NAMESPACE=us-west-org vault login -field=token -no-store -method=oidc role=campaign-admin > token.txt
# Read the secret in us-east-org namespace using a token issued in us-west-org namespace
VAULT_NAMESPACE=us-east-org VAULT_TOKEN=$(cat token.txt) vault kv get kv-marketing/campaign