From 2824616ba6588e6b64933c2a3d044cb64091c24a Mon Sep 17 00:00:00 2001 From: Ryan Petrello Date: Thu, 28 Feb 2019 13:10:44 -0500 Subject: [PATCH] add support for CyberArk Conjur (API v5) --- Makefile | 5 +- awx/main/credential_plugins/conjur.py | 92 +++++++++++++++++++ setup.py | 1 + .../awx.egg-info/entry_points.txt | 1 + tools/docker-credential-plugins-override.yml | 28 ++++++ tools/docker-hashivault-override.yml | 15 --- 6 files changed, 125 insertions(+), 17 deletions(-) create mode 100644 awx/main/credential_plugins/conjur.py create mode 100644 tools/docker-credential-plugins-override.yml delete mode 100644 tools/docker-hashivault-override.yml diff --git a/Makefile b/Makefile index 294d940ba1..e0cfc4b78f 100644 --- a/Makefile +++ b/Makefile @@ -575,8 +575,9 @@ docker-compose: docker-auth docker-compose-cluster: docker-auth CURRENT_UID=$(shell id -u) TAG=$(COMPOSE_TAG) DEV_DOCKER_TAG_BASE=$(DEV_DOCKER_TAG_BASE) docker-compose -f tools/docker-compose-cluster.yml up -docker-compose-hashivault: docker-auth - CURRENT_UID=$(shell id -u) TAG=$(COMPOSE_TAG) DEV_DOCKER_TAG_BASE=$(DEV_DOCKER_TAG_BASE) docker-compose -f tools/docker-compose.yml -f tools/docker-hashivault-override.yml up --no-recreate awx +docker-compose-credential-plugins: docker-auth + echo -e "\033[0;31mTo generate a CyberArk Conjur API key: docker exec -it tools_conjur_1 conjurctl account create quick-start\033[0m" + CURRENT_UID=$(shell id -u) TAG=$(COMPOSE_TAG) DEV_DOCKER_TAG_BASE=$(DEV_DOCKER_TAG_BASE) docker-compose -f tools/docker-compose.yml -f tools/docker-credential-plugins-override.yml up --no-recreate awx docker-compose-test: docker-auth cd tools && CURRENT_UID=$(shell id -u) TAG=$(COMPOSE_TAG) DEV_DOCKER_TAG_BASE=$(DEV_DOCKER_TAG_BASE) docker-compose run --rm --service-ports awx /bin/bash diff --git a/awx/main/credential_plugins/conjur.py b/awx/main/credential_plugins/conjur.py new file mode 100644 index 0000000000..f5b6ae23d0 --- /dev/null +++ b/awx/main/credential_plugins/conjur.py @@ -0,0 +1,92 @@ +from .plugin import CredentialPlugin + +import base64 +import io +from urllib.parse import urljoin, quote_plus + +from django.utils.translation import ugettext_lazy as _ +import requests + + +conjur_inputs = { + 'fields': [{ + 'id': 'url', + 'label': _('Conjur URL'), + 'type': 'string', + }, { + 'id': 'api_key', + 'label': _('API Key'), + 'type': 'string', + 'secret': True, + }, { + 'id': 'account', + 'label': _('Account'), + 'type': 'string', + }, { + 'id': 'username', + 'label': _('Username'), + 'type': 'string', + }, { + 'id': 'cacert', + 'label': _('Public Key Certificate'), + 'type': 'string', + 'multiline': True + }], + 'metadata': [{ + 'id': 'secret_path', + 'label': _('Secret Identifier'), + 'type': 'string', + 'help_text': _('The identifier for the secret e.g., /some/identifier'), + }, { + 'id': 'secret_version', + 'label': _('Secret Version'), + 'type': 'string', + 'help_text': _('Used to specify a specific secret version (if left empty, the latest version will be used).'), + }], + 'required': ['url', 'api_key', 'account', 'username'], +} + + +def conjur_backend(raw, **kwargs): + url = kwargs['url'] + api_key = kwargs['api_key'] + account = quote_plus(kwargs['account']) + username = quote_plus(kwargs['username']) + secret_path = quote_plus(kwargs['secret_path']) + version = kwargs.get('secret_version') + cert = io.StringIO() + cert.write(kwargs.get('cacert', '')) + + # https://www.conjur.org/api.html#authentication-authenticate-post + resp = requests.post( + urljoin(url, '/'.join(['authn', account, username, 'authenticate'])), + headers={'Content-Type': 'text/plain'}, + data=api_key, + verify=cert + ) + resp.raise_for_status() + token = base64.b64encode(resp.content).decode('utf-8') + + # https://www.conjur.org/api.html#secrets-retrieve-a-secret-get + path = urljoin(url, '/'.join([ + 'secrets', + account, + 'variable', + secret_path + ])) + if version: + path = '?'.join([path, version]) + resp = requests.get( + path, + headers={'Authorization': 'Token token="{}"'.format(token)}, + verify=cert + ) + resp.raise_for_status() + return resp.text + + +conjur_plugin = CredentialPlugin( + 'CyberArk Conjur Secret Lookup', + inputs=conjur_inputs, + backend=conjur_backend +) diff --git a/setup.py b/setup.py index 1fadc25dcf..957976a5c5 100755 --- a/setup.py +++ b/setup.py @@ -115,6 +115,7 @@ setup( 'awx-manage = awx:manage', ], 'awx.credential_plugins': [ + 'conjur = awx.main.credential_plugins.conjur:conjur_plugin', 'hashivault_kv = awx.main.credential_plugins.hashivault:hashivault_kv_plugin', 'hashivault_ssh = awx.main.credential_plugins.hashivault:hashivault_ssh_plugin', 'azure_kv = awx.main.credential_plugins.azure_kv:azure_keyvault_plugin', diff --git a/tools/docker-compose/awx.egg-info/entry_points.txt b/tools/docker-compose/awx.egg-info/entry_points.txt index f1832e730c..dfc186681d 100644 --- a/tools/docker-compose/awx.egg-info/entry_points.txt +++ b/tools/docker-compose/awx.egg-info/entry_points.txt @@ -3,6 +3,7 @@ tower-manage = awx:manage awx-manage = awx:manage [awx.credential_plugins] +conjur = awx.main.credential_plugins.conjur:conjur_plugin hashivault_kv = awx.main.credential_plugins.hashivault:hashivault_kv_plugin hashivault_ssh = awx.main.credential_plugins.hashivault:hashivault_ssh_plugin azure_kv = awx.main.credential_plugins.azure_kv:azure_keyvault_plugin diff --git a/tools/docker-credential-plugins-override.yml b/tools/docker-credential-plugins-override.yml new file mode 100644 index 0000000000..07e596e218 --- /dev/null +++ b/tools/docker-credential-plugins-override.yml @@ -0,0 +1,28 @@ +version: '2' +services: + # Primary Tower Development Container link + awx: + links: + - hashivault + - conjur + hashivault: + image: vault:1.0.1 + container_name: tools_hashivault_1 + ports: + - '8200:8200' + cap_add: + - IPC_LOCK + environment: + VAULT_DEV_ROOT_TOKEN_ID: 'vaultdev' + + conjur: + image: cyberark/conjur + command: server -p 8300 + environment: + DATABASE_URL: postgres://postgres@postgres/postgres + CONJUR_DATA_KEY: 'dveUwOI/71x9BPJkIgvQRRBF3SdASc+HP4CUGL7TKvM=' + depends_on: [ postgres ] + links: + - postgres + ports: + - "8300:8300" diff --git a/tools/docker-hashivault-override.yml b/tools/docker-hashivault-override.yml deleted file mode 100644 index 8ada54abcb..0000000000 --- a/tools/docker-hashivault-override.yml +++ /dev/null @@ -1,15 +0,0 @@ -version: '2' -services: - # Primary Tower Development Container link - awx: - links: - - hashivault - hashivault: - image: vault:1.0.1 - container_name: tools_hashivault_1 - ports: - - '8200:8200' - cap_add: - - IPC_LOCK - environment: - VAULT_DEV_ROOT_TOKEN_ID: 'vaultdev'