Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 5 commits into from
Feb 9, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -538,7 +538,8 @@ docker-compose: awx/projects docker-compose-sources
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 \
-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-credential-plugins: awx/projects docker-compose-sources
47 changes: 44 additions & 3 deletions tools/docker-compose/README.md
Original file line number Diff line number Diff line change
@@ -538,13 +538,15 @@ To create a secret connected to this vault in AWX you can run the following play
```bash
export CONTROLLER_USERNAME=<your username>
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:
* 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 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`.
If you have a playbook like:
@@ -559,7 +561,46 @@ If you have a playbook like:
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.
This was discovered by inspecting the secret with the vault CLI, which may help with future troubleshooting.
Original file line number Diff line number Diff line change
@@ -34,6 +34,7 @@ ldap_cert_subject: "/C=US/ST=NC/L=Durham/O=awx/CN="
enable_vault: false
vault_tls: false
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_extensions:
- "subjectAltName = DNS:tools_vault_1, DNS:localhost"
7 changes: 5 additions & 2 deletions tools/docker-compose/ansible/roles/sources/tasks/ldap.yml
Original file line number Diff line number Diff line change
@@ -7,12 +7,15 @@
- "{{ ldap_cert_dir }}"
- "{{ ldap_diff_dir }}"

- name: include vault vars
include_vars: "{{ hashivault_vars_file }}"

- 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 }}"'
args:
creates: "{{ ldap_public_key_file }}"

- name: Copy ldap.diff
copy:
src: "ldap.ldif"
ansible.builtin.template:
src: "ldap.ldif.j2"
dest: "{{ ldap_diff_dir }}/ldap.ldif"
Original file line number Diff line number Diff line change
@@ -84,3 +84,16 @@ objectClass: top
objectClass: groupOfNames
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 %}
7 changes: 6 additions & 1 deletion tools/docker-compose/ansible/roles/vault/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
---
vault_file: "{{ sources_dest }}/secrets/vault_init.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_client_cert: "{{ vault_cert_dir }}/client.crt"
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"
122 changes: 122 additions & 0 deletions tools/docker-compose/ansible/roles/vault/tasks/initialize.yml
Original file line number Diff line number Diff line change
@@ -92,6 +92,128 @@
validate_certs: false
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:
- name: Stop the vault
community.docker.docker_compose:
110 changes: 102 additions & 8 deletions tools/docker-compose/ansible/roles/vault/tasks/plumb.yml
Original file line number Diff line number Diff line change
@@ -38,7 +38,6 @@
controller_host: "{{ awx_host }}"
controller_username: admin
controller_password: "{{ admin_password }}"

validate_certs: false
injectors:
extra_vars:
@@ -51,32 +50,127 @@
secret: true
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:
credential_type: "{{ custom_vault_cred_type.id }}"
controller_host: "{{ awx_host }}"
controller_username: admin
controller_password: "{{ admin_password }}"

validate_certs: false
name: Credential From Vault
name: Credential From HashiCorp Vault via Token Auth
inputs: {}
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:
input_field_name: password
target_credential: "{{ custom_credential.id }}"
target_credential: "{{ custom_credential_via_token.id }}"
source_credential: "{{ vault_cred.id }}"
controller_host: "{{ awx_host }}"
controller_username: admin
controller_password: "{{ admin_password }}"

validate_certs: false
metadata:
auth_path: ""
secret_backend: "my_engine"
secret_key: "my_key"
secret_path: "/my_root/my_folder"
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: ""