Add ldap support to vault container in docker dev environment (#14777)

* add ldap_auth mount and configure it

* added in key engines, userpass auth method, still needs testing

* add policies and fix ldap_user

* start awx automation for vault demo and move ldap

* update docs with new flags/new credentials
This commit is contained in:
Jake Jackson
2024-02-09 15:19:17 -05:00
committed by GitHub
parent 2e5306ae8e
commit 519fd22bec
8 changed files with 295 additions and 15 deletions

View File

@@ -538,7 +538,8 @@ docker-compose: awx/projects docker-compose-sources
ansible-galaxy install --ignore-certs -r tools/docker-compose/ansible/requirements.yml; ansible-galaxy install --ignore-certs -r tools/docker-compose/ansible/requirements.yml;
ansible-playbook -i tools/docker-compose/inventory tools/docker-compose/ansible/initialize_containers.yml \ ansible-playbook -i tools/docker-compose/inventory tools/docker-compose/ansible/initialize_containers.yml \
-e enable_vault=$(VAULT) \ -e enable_vault=$(VAULT) \
-e vault_tls=$(VAULT_TLS); -e vault_tls=$(VAULT_TLS) \
-e enable_ldap=$(LDAP);
$(DOCKER_COMPOSE) -f tools/docker-compose/_sources/docker-compose.yml $(COMPOSE_OPTS) up $(COMPOSE_UP_OPTS) --remove-orphans $(DOCKER_COMPOSE) -f tools/docker-compose/_sources/docker-compose.yml $(COMPOSE_OPTS) up $(COMPOSE_UP_OPTS) --remove-orphans
docker-compose-credential-plugins: awx/projects docker-compose-sources docker-compose-credential-plugins: awx/projects docker-compose-sources

View File

@@ -538,13 +538,15 @@ To create a secret connected to this vault in AWX you can run the following play
```bash ```bash
export CONTROLLER_USERNAME=<your username> export CONTROLLER_USERNAME=<your username>
export CONTROLLER_PASSWORD=<your password> export CONTROLLER_PASSWORD=<your password>
ansible-playbook tools/docker-compose/ansible/plumb_vault.yml ansible-playbook tools/docker-compose/ansible/plumb_vault.yml -e enable_ldap=false
``` ```
This will create the following items in your AWX instance: This will create the following items in your AWX instance:
* A credential called `Vault Lookup Cred` tied to the vault instance. * A credential called `Vault Lookup Cred` tied to the vault instance.
* A credential called `Vault UserPass Lookup Cred` tied to the vault instance.
* A custom credential type called `Vault Custom Cred Type`. * A custom credential type called `Vault Custom Cred Type`.
* A credential called `Credential From Vault` which is of the created type using the `Vault Lookup Cred` to get the password. * A credential called `Credential From HashiCorp Vault via Token Auth` which is of the created type using the `Vault Lookup Cred` to get the secret.
* A credential called `Credential From HashiCorp Vault via UserPass Auth` which is of the created type using the `Vault Userpass Lookup Cred` to get the secret.
The custom credential type adds a variable when used in a playbook called `the_secret_from_vault`. The custom credential type adds a variable when used in a playbook called `the_secret_from_vault`.
If you have a playbook like: If you have a playbook like:
@@ -559,7 +561,46 @@ If you have a playbook like:
var: the_secret_from_vault var: the_secret_from_vault
``` ```
And run it through AWX with the credential `Credential From Vault` tied to it, the debug should result in `this_is_the_secret_value` And run it through AWX with the credential `Credential From Vault via Token Auth` tied to it, the debug should result in `this_is_the_secret_value`. If you run it through AWX with the credential `Credential From Vault via Userpass Auth`, the debug should result in `this_is_the_userpass_secret_value`.
### HashiVault with LDAP
If you wish to have your OpenLDAP container connected to the Vault container, you will first need to have the OpenLDAP container running alongside AWX and Vault.
```bash
VAULT=true LDAP=true make docker-compose
```
Similar to the above, you will need to unseal the vault before we can run the other needed playbooks.
```bash
ansible-playbook tools/docker-compose/ansible/unseal_vault.yml
```
Now that the vault is unsealed, we can plumb the vault container now while passing true to enable_ldap extra var.
```bash
export CONTROLLER_USERNAME=<your username>
export CONTROLLER_PASSWORD=<your password>
ansible-playbook tools/docker-compose/ansible/plumb_vault.yml -e enable_ldap=true
```
This will populate your AWX instance with LDAP specific items.
- A vault LDAP Lookup Cred tied to the LDAP `awx_ldap_vault` user called `Vault LDAP Lookup Cred`
- A credential called `Credential From HashiCorp Vault via LDAP Auth` which is of the created type using the `Vault LDAP Lookup Cred` to get the secret.
And run it through AWX with the credential `Credential From HashiCorp Vault via LDAP Auth` tied to it, the debug should result in `this_is_the_ldap_secret_value`.
The extremely non-obvious input is the fact that the fact prefixes "data/" unexpectedly. The extremely non-obvious input is the fact that the fact prefixes "data/" unexpectedly.
This was discovered by inspecting the secret with the vault CLI, which may help with future troubleshooting. This was discovered by inspecting the secret with the vault CLI, which may help with future troubleshooting.

View File

@@ -34,6 +34,7 @@ ldap_cert_subject: "/C=US/ST=NC/L=Durham/O=awx/CN="
enable_vault: false enable_vault: false
vault_tls: false vault_tls: false
hashivault_cert_dir: '{{ sources_dest }}/vault_certs' hashivault_cert_dir: '{{ sources_dest }}/vault_certs'
hashivault_vars_file: '../vault/defaults/main.yml'
hashivault_server_cert_subject: "/C=US/ST=NC/L=Durham/O=awx/CN=tools-vault-1" hashivault_server_cert_subject: "/C=US/ST=NC/L=Durham/O=awx/CN=tools-vault-1"
hashivault_server_cert_extensions: hashivault_server_cert_extensions:
- "subjectAltName = DNS:tools_vault_1, DNS:localhost" - "subjectAltName = DNS:tools_vault_1, DNS:localhost"

View File

@@ -7,12 +7,15 @@
- "{{ ldap_cert_dir }}" - "{{ ldap_cert_dir }}"
- "{{ ldap_diff_dir }}" - "{{ ldap_diff_dir }}"
- name: include vault vars
include_vars: "{{ hashivault_vars_file }}"
- name: General LDAP cert - name: General LDAP cert
command: 'openssl req -new -x509 -days 365 -nodes -out {{ ldap_public_key_file }} -keyout {{ ldap_private_key_file }} -subj "{{ ldap_cert_subject }}"' command: 'openssl req -new -x509 -days 365 -nodes -out {{ ldap_public_key_file }} -keyout {{ ldap_private_key_file }} -subj "{{ ldap_cert_subject }}"'
args: args:
creates: "{{ ldap_public_key_file }}" creates: "{{ ldap_public_key_file }}"
- name: Copy ldap.diff - name: Copy ldap.diff
copy: ansible.builtin.template:
src: "ldap.ldif" src: "ldap.ldif.j2"
dest: "{{ ldap_diff_dir }}/ldap.ldif" dest: "{{ ldap_diff_dir }}/ldap.ldif"

View File

@@ -84,3 +84,16 @@ objectClass: top
objectClass: groupOfNames objectClass: groupOfNames
member: cn=awx_ldap_org_admin,ou=users,dc=example,dc=org member: cn=awx_ldap_org_admin,ou=users,dc=example,dc=org
{% if enable_ldap|bool and enable_vault|bool %}
dn: cn={{ vault_ldap_username }},ou=users,dc=example,dc=org
changetype: add
mail: vault@example.org
sn: LdapVaultAdmin
cn: {{ vault_ldap_username }}
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
userPassword: {{ vault_ldap_password }}
givenName: awx
{% endif %}

View File

@@ -1,7 +1,12 @@
--- ---
vault_file: "{{ sources_dest }}/secrets/vault_init.yml" vault_file: "{{ sources_dest }}/secrets/vault_init.yml"
admin_password_file: "{{ sources_dest }}/secrets/admin_password.yml" admin_password_file: "{{ sources_dest }}/secrets/admin_password.yml"
vault_cert_dir: '{{ sources_dest }}/vault_certs' vault_cert_dir: "{{ sources_dest }}/vault_certs"
vault_server_cert: "{{ vault_cert_dir }}/server.crt" vault_server_cert: "{{ vault_cert_dir }}/server.crt"
vault_client_cert: "{{ vault_cert_dir }}/client.crt" vault_client_cert: "{{ vault_cert_dir }}/client.crt"
vault_client_key: "{{ vault_cert_dir }}/client.key" vault_client_key: "{{ vault_cert_dir }}/client.key"
ldap_ldif: "{{ sources_dest }}/ldap.ldifs/ldap.ldif"
vault_ldap_username: "awx_ldap_vault"
vault_ldap_password: "vault123"
vault_userpass_username: "awx_userpass_admin"
vault_userpass_password: "userpass123"

View File

@@ -92,6 +92,128 @@
validate_certs: false validate_certs: false
token: "{{ Initial_Root_Token }}" token: "{{ Initial_Root_Token }}"
- name: Configure the vault ldap auth
block:
- name: Create ldap auth mount
flowerysong.hvault.write:
path: "sys/auth/ldap"
vault_addr: "{{ vault_addr_from_host }}"
validate_certs: false
token: "{{ Initial_Root_Token }}"
data:
type: "ldap"
register: vault_auth_ldap
changed_when: vault_auth_ldap.result.errors | default([]) | length == 0
failed_when:
- vault_auth_ldap.result.errors | default([]) | length > 0
- "'path is already in use at ldap/' not in vault_auth_ldap.result.errors | default([])"
- name: Create ldap engine
flowerysong.hvault.engine:
path: "ldap_engine"
type: "kv"
vault_addr: "{{ vault_addr_from_host }}"
validate_certs: false
token: "{{ Initial_Root_Token }}"
- name: Create a ldap secret
flowerysong.hvault.kv:
mount_point: "ldap_engine/ldaps_root"
key: "ldap_secret"
value:
my_key: "this_is_the_ldap_secret_value"
vault_addr: "{{ vault_addr_from_host }}"
validate_certs: false
token: "{{ Initial_Root_Token }}"
- name: Configure ldap auth
flowerysong.hvault.ldap_config:
vault_addr: "{{ vault_addr_from_host }}"
validate_certs: false
token: "{{ Initial_Root_Token }}"
url: "ldap://ldap:1389"
binddn: "cn=awx_ldap_vault,ou=users,dc=example,dc=org"
bindpass: "vault123"
userdn: "ou=users,dc=example,dc=org"
deny_null_bind: "false"
discoverdn: "true"
- name: Create ldap access policy
flowerysong.hvault.policy:
vault_addr: "{{ vault_addr_from_host }}"
validate_certs: false
token: "{{ Initial_Root_Token }}"
name: "ldap_engine"
policy:
ldap_engine/*: [create, read, update, delete, list]
sys/mounts:/*: [create, read, update, delete, list]
sys/mounts: [read]
- name: Add awx_ldap_vault user to auth_method
flowerysong.hvault.ldap_user:
vault_addr: "{{ vault_addr_from_host }}"
validate_certs: false
token: "{{ Initial_Root_Token }}"
state: present
name: "{{ vault_ldap_username }}"
policies:
- "ldap_engine"
when: enable_ldap | bool
- name: Create userpass engine
flowerysong.hvault.engine:
path: "userpass_engine"
type: "kv"
vault_addr: "{{ vault_addr_from_host }}"
validate_certs: false
token: "{{ Initial_Root_Token }}"
- name: Create a userpass secret
flowerysong.hvault.kv:
mount_point: "userpass_engine/userpass_root"
key: "userpass_secret"
value:
my_key: "this_is_the_userpass_secret_value"
vault_addr: "{{ vault_addr_from_host }}"
validate_certs: false
token: "{{ Initial_Root_Token }}"
- name: Create userpass access policy
flowerysong.hvault.policy:
vault_addr: "{{ vault_addr_from_host }}"
validate_certs: false
token: "{{ Initial_Root_Token }}"
name: "userpass_engine"
policy:
userpass_engine/*: [create, read, update, delete, list]
sys/mounts:/*: [create, read, update, delete, list]
sys/mounts: [read]
- name: Create userpass auth mount
flowerysong.hvault.write:
path: "sys/auth/userpass"
vault_addr: "{{ vault_addr_from_host }}"
validate_certs: false
token: "{{ Initial_Root_Token }}"
data:
type: "userpass"
register: vault_auth_userpass
changed_when: vault_auth_userpass.result.errors | default([]) | length == 0
failed_when:
- vault_auth_userpass.result.errors | default([]) | length > 0
- "'path is already in use at userpass/' not in vault_auth_userpass.result.errors | default([])"
- name: Add awx_userpass_admin user to auth_method
flowerysong.hvault.write:
vault_addr: "{{ vault_addr_from_host }}"
validate_certs: false
token: "{{ Initial_Root_Token }}"
path: "auth/userpass/users/{{ vault_userpass_username }}"
data:
password: "{{ vault_userpass_password }}"
policies:
- "userpass_engine"
always: always:
- name: Stop the vault - name: Stop the vault
community.docker.docker_compose: community.docker.docker_compose:

View File

@@ -38,7 +38,6 @@
controller_host: "{{ awx_host }}" controller_host: "{{ awx_host }}"
controller_username: admin controller_username: admin
controller_password: "{{ admin_password }}" controller_password: "{{ admin_password }}"
validate_certs: false validate_certs: false
injectors: injectors:
extra_vars: extra_vars:
@@ -51,28 +50,26 @@
secret: true secret: true
register: custom_vault_cred_type register: custom_vault_cred_type
- name: Create a credential of the custom type - name: Create a credential of the custom type for token auth
awx.awx.credential: awx.awx.credential:
credential_type: "{{ custom_vault_cred_type.id }}" credential_type: "{{ custom_vault_cred_type.id }}"
controller_host: "{{ awx_host }}" controller_host: "{{ awx_host }}"
controller_username: admin controller_username: admin
controller_password: "{{ admin_password }}" controller_password: "{{ admin_password }}"
validate_certs: false validate_certs: false
name: Credential From Vault name: Credential From HashiCorp Vault via Token Auth
inputs: {} inputs: {}
organization: Default organization: Default
register: custom_credential register: custom_credential_via_token
- name: Use the Vault Credential For the new credential - name: Use the Token Vault Credential For the new credential
awx.awx.credential_input_source: awx.awx.credential_input_source:
input_field_name: password input_field_name: password
target_credential: "{{ custom_credential.id }}" target_credential: "{{ custom_credential_via_token.id }}"
source_credential: "{{ vault_cred.id }}" source_credential: "{{ vault_cred.id }}"
controller_host: "{{ awx_host }}" controller_host: "{{ awx_host }}"
controller_username: admin controller_username: admin
controller_password: "{{ admin_password }}" controller_password: "{{ admin_password }}"
validate_certs: false validate_certs: false
metadata: metadata:
auth_path: "" auth_path: ""
@@ -80,3 +77,100 @@
secret_key: "my_key" secret_key: "my_key"
secret_path: "/my_root/my_folder" secret_path: "/my_root/my_folder"
secret_version: "" secret_version: ""
- name: Create a HashiCorp Vault Credential for LDAP
awx.awx.credential:
credential_type: HashiCorp Vault Secret Lookup
name: Vault LDAP Lookup Cred
organization: Default
controller_host: "{{ awx_host }}"
controller_username: admin
controller_password: "{{ admin_password }}"
validate_certs: false
inputs:
api_version: "v1"
default_auth_path: "ldap"
kubernetes_role: ""
namespace: ""
url: "{{ vault_addr_from_container }}"
username: "{{ vault_ldap_username }}"
password: "{{ vault_ldap_password }}"
register: vault_ldap_cred
when: enable_ldap | bool
- name: Create a credential from the Vault LDAP Custom Cred Type
awx.awx.credential:
credential_type: "{{ custom_vault_cred_type.id }}"
controller_host: "{{ awx_host }}"
controller_username: admin
controller_password: "{{ admin_password }}"
validate_certs: false
name: Credential From HashiCorp Vault via LDAP Auth
inputs: {}
organization: Default
register: custom_credential_via_ldap
when: enable_ldap | bool
- name: Use the Vault LDAP Credential the new credential
awx.awx.credential_input_source:
input_field_name: password
target_credential: "{{ custom_credential_via_ldap.id }}"
source_credential: "{{ vault_ldap_cred.id }}"
controller_host: "{{ awx_host }}"
controller_username: admin
controller_password: "{{ admin_password }}"
validate_certs: false
metadata:
auth_path: ""
secret_backend: "ldap_engine"
secret_key: "my_key"
secret_path: "ldaps_root/ldap_secret"
secret_version: ""
when: enable_ldap | bool
- name: Create a HashiCorp Vault Credential for UserPass
awx.awx.credential:
credential_type: HashiCorp Vault Secret Lookup
name: Vault UserPass Lookup Cred
organization: Default
controller_host: "{{ awx_host }}"
controller_username: admin
controller_password: "{{ admin_password }}"
validate_certs: false
inputs:
api_version: "v1"
default_auth_path: "userpass"
kubernetes_role: ""
namespace: ""
url: "{{ vault_addr_from_container }}"
username: "{{ vault_userpass_username }}"
password: "{{ vault_userpass_password }}"
register: vault_userpass_cred
- name: Create a credential from the Vault UserPass Custom Cred Type
awx.awx.credential:
credential_type: "{{ custom_vault_cred_type.id }}"
controller_host: "{{ awx_host }}"
controller_username: admin
controller_password: "{{ admin_password }}"
validate_certs: false
name: Credential From HashiCorp Vault via UserPass Auth
inputs: {}
organization: Default
register: custom_credential_via_userpass
- name: Use the Vault UserPass Credential the new credential
awx.awx.credential_input_source:
input_field_name: password
target_credential: "{{ custom_credential_via_userpass.id }}"
source_credential: "{{ vault_userpass_cred.id }}"
controller_host: "{{ awx_host }}"
controller_username: admin
controller_password: "{{ admin_password }}"
validate_certs: false
metadata:
auth_path: ""
secret_backend: "userpass_engine"
secret_key: "my_key"
secret_path: "userpass_root/userpass_secret"
secret_version: ""