mirror of
https://github.com/ansible/awx.git
synced 2026-05-11 03:17:38 -02:30
Merge pull request #9542 from ryanpetrello/centrify
Add support for Centrify Vault as a credential plugin replaces #8952 cc @surbhijain1502 @Asharma-bhavna @badrogh Reviewed-by: Ryan Petrello <None> Reviewed-by: Jake McDermott <yo@jakemcdermott.me> Reviewed-by: Chris Meyers <None>
This commit is contained in:
142
awx/main/credential_plugins/centrify_vault.py
Normal file
142
awx/main/credential_plugins/centrify_vault.py
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
from .plugin import CredentialPlugin, raise_for_status
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from urllib.parse import urljoin
|
||||||
|
import requests
|
||||||
|
pas_inputs = {
|
||||||
|
'fields': [{
|
||||||
|
'id': 'url',
|
||||||
|
'label': _('Centrify Tenant URL'),
|
||||||
|
'type': 'string',
|
||||||
|
'help_text': _('Centrify Tenant URL'),
|
||||||
|
'format': 'url',
|
||||||
|
}, {
|
||||||
|
'id':'client_id',
|
||||||
|
'label':_('Centrify API User'),
|
||||||
|
'type':'string',
|
||||||
|
'help_text': _('Centrify API User, having necessary permissions as mentioned in support doc'),
|
||||||
|
|
||||||
|
}, {
|
||||||
|
'id':'client_password',
|
||||||
|
'label':_('Centrify API Password'),
|
||||||
|
'type':'string',
|
||||||
|
'help_text': _('Password of Centrify API User with necessary permissions'),
|
||||||
|
'secret':True,
|
||||||
|
},{
|
||||||
|
'id':'oauth_application_id',
|
||||||
|
'label':_('OAuth2 Application ID'),
|
||||||
|
'type':'string',
|
||||||
|
'help_text': _('Application ID of the configured OAuth2 Client (defaults to \'awx\')'),
|
||||||
|
'default': 'awx',
|
||||||
|
},{
|
||||||
|
'id':'oauth_scope',
|
||||||
|
'label':_('OAuth2 Scope'),
|
||||||
|
'type':'string',
|
||||||
|
'help_text': _('Scope of the configured OAuth2 Client (defaults to \'awx\')'),
|
||||||
|
'default': 'awx',
|
||||||
|
}],
|
||||||
|
'metadata': [{
|
||||||
|
'id': 'account-name',
|
||||||
|
'label': _('Account Name'),
|
||||||
|
'type': 'string',
|
||||||
|
'help_text': _('Local system account or Domain account name enrolled in Centrify Vault. eg. (root or DOMAIN/Administrator)'),
|
||||||
|
},{
|
||||||
|
'id': 'system-name',
|
||||||
|
'label': _('System Name'),
|
||||||
|
'type': 'string',
|
||||||
|
'help_text': _('Machine Name enrolled with in Centrify Portal'),
|
||||||
|
}],
|
||||||
|
'required': ['url', 'account-name', 'system-name','client_id','client_password'],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# generate bearer token to authenticate with PAS portal, Input : Client ID, Client Secret
|
||||||
|
def handle_auth(**kwargs):
|
||||||
|
post_data = {
|
||||||
|
"grant_type": "client_credentials",
|
||||||
|
"scope": kwargs['oauth_scope']
|
||||||
|
}
|
||||||
|
response = requests.post(
|
||||||
|
kwargs['endpoint'],
|
||||||
|
data = post_data,
|
||||||
|
auth = (kwargs['client_id'],kwargs['client_password']),
|
||||||
|
verify = True,
|
||||||
|
timeout = (5, 30)
|
||||||
|
)
|
||||||
|
raise_for_status(response)
|
||||||
|
try:
|
||||||
|
return response.json()['access_token']
|
||||||
|
except KeyError:
|
||||||
|
raise RuntimeError('OAuth request to tenant was unsuccessful')
|
||||||
|
|
||||||
|
|
||||||
|
# fetch the ID of system with RedRock query, Input : System Name, Account Name
|
||||||
|
def get_ID(**kwargs):
|
||||||
|
endpoint = urljoin(kwargs['url'],'/Redrock/query')
|
||||||
|
name=" Name='{0}' and User='{1}'".format(kwargs['system_name'],kwargs['acc_name'])
|
||||||
|
query = 'Select ID from VaultAccount where {0}'.format(name)
|
||||||
|
post_headers = {
|
||||||
|
"Authorization": "Bearer " + kwargs['access_token'],
|
||||||
|
"X-CENTRIFY-NATIVE-CLIENT":"true"
|
||||||
|
}
|
||||||
|
response = requests.post(
|
||||||
|
endpoint,
|
||||||
|
json = {'Script': query},
|
||||||
|
headers = post_headers,
|
||||||
|
verify = True,
|
||||||
|
timeout = (5, 30)
|
||||||
|
)
|
||||||
|
raise_for_status(response)
|
||||||
|
try:
|
||||||
|
result_str = response.json()["Result"]["Results"]
|
||||||
|
return result_str[0]["Row"]["ID"]
|
||||||
|
except (IndexError, KeyError):
|
||||||
|
raise RuntimeError("Error Detected!! Check the Inputs")
|
||||||
|
|
||||||
|
|
||||||
|
# CheckOut Password from Centrify Vault, Input : ID
|
||||||
|
def get_passwd(**kwargs):
|
||||||
|
endpoint = urljoin(kwargs['url'],'/ServerManage/CheckoutPassword')
|
||||||
|
post_headers = {
|
||||||
|
"Authorization": "Bearer " + kwargs['access_token'],
|
||||||
|
"X-CENTRIFY-NATIVE-CLIENT":"true"
|
||||||
|
}
|
||||||
|
response = requests.post(
|
||||||
|
endpoint,
|
||||||
|
json = {'ID': kwargs['acc_id']},
|
||||||
|
headers = post_headers,
|
||||||
|
verify = True,
|
||||||
|
timeout = (5, 30)
|
||||||
|
)
|
||||||
|
raise_for_status(response)
|
||||||
|
try:
|
||||||
|
return response.json()["Result"]["Password"]
|
||||||
|
except KeyError:
|
||||||
|
raise RuntimeError("Password Not Found")
|
||||||
|
|
||||||
|
|
||||||
|
def centrify_backend(**kwargs):
|
||||||
|
url = kwargs.get('url')
|
||||||
|
acc_name = kwargs.get('account-name')
|
||||||
|
system_name = kwargs.get('system-name')
|
||||||
|
client_id = kwargs.get('client_id')
|
||||||
|
client_password = kwargs.get('client_password')
|
||||||
|
app_id = kwargs.get('oauth_application_id', 'awx')
|
||||||
|
endpoint = urljoin(url, f'/oauth2/token/{app_id}')
|
||||||
|
endpoint = {
|
||||||
|
'endpoint': endpoint,
|
||||||
|
'client_id': client_id,
|
||||||
|
'client_password': client_password,
|
||||||
|
'oauth_scope': kwargs.get('oauth_scope', 'awx')
|
||||||
|
}
|
||||||
|
token = handle_auth(**endpoint)
|
||||||
|
get_id_args = {'system_name':system_name,'acc_name':acc_name,'url':url,'access_token':token}
|
||||||
|
acc_id = get_ID(**get_id_args)
|
||||||
|
get_pwd_args = {'url':url,'acc_id':acc_id,'access_token':token}
|
||||||
|
return get_passwd(**get_pwd_args)
|
||||||
|
|
||||||
|
|
||||||
|
centrify_plugin = CredentialPlugin(
|
||||||
|
'Centrify Vault Credential Provider Lookup',
|
||||||
|
inputs=pas_inputs,
|
||||||
|
backend=centrify_backend
|
||||||
|
)
|
||||||
20
awx/main/migrations/0133_centrify_vault_credtype.py
Normal file
20
awx/main/migrations/0133_centrify_vault_credtype.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
from awx.main.models import CredentialType
|
||||||
|
from awx.main.utils.common import set_current_apps
|
||||||
|
|
||||||
|
|
||||||
|
def setup_tower_managed_defaults(apps, schema_editor):
|
||||||
|
set_current_apps(apps)
|
||||||
|
CredentialType.setup_tower_managed_defaults()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('main', '0132_instancegroup_is_container_group'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(setup_tower_managed_defaults),
|
||||||
|
]
|
||||||
@@ -79,6 +79,7 @@ def test_default_cred_types():
|
|||||||
'aws',
|
'aws',
|
||||||
'azure_kv',
|
'azure_kv',
|
||||||
'azure_rm',
|
'azure_rm',
|
||||||
|
'centrify_vault_kv',
|
||||||
'conjur',
|
'conjur',
|
||||||
'galaxy_api_token',
|
'galaxy_api_token',
|
||||||
'gce',
|
'gce',
|
||||||
|
|||||||
@@ -332,3 +332,52 @@ def test_aim_credential_source(run_module, admin_user, organization, source_cred
|
|||||||
assert cis.source_credential.name == source_cred_aim_alt.name
|
assert cis.source_credential.name == source_cred_aim_alt.name
|
||||||
assert cis.target_credential.name == tgt_cred.name
|
assert cis.target_credential.name == tgt_cred.name
|
||||||
assert cis.input_field_name == 'password'
|
assert cis.input_field_name == 'password'
|
||||||
|
|
||||||
|
|
||||||
|
# Test Centrify Vault secret credential source
|
||||||
|
@pytest.fixture
|
||||||
|
def source_cred_centrify_secret(organization):
|
||||||
|
# Make a credential type which will be used by the credential
|
||||||
|
ct = CredentialType.defaults['centrify_vault_kv']()
|
||||||
|
ct.save()
|
||||||
|
return Credential.objects.create(
|
||||||
|
name='Centrify vault secret Cred',
|
||||||
|
credential_type=ct,
|
||||||
|
inputs={
|
||||||
|
"url": "https://tenant_id.my.centrify-dev.net",
|
||||||
|
"client_id": "secretuser@tenant",
|
||||||
|
"client_password": "secretuserpassword",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_centrify_vault_credential_source(run_module, admin_user, organization, source_cred_centrify_secret, silence_deprecation):
|
||||||
|
ct = CredentialType.defaults['ssh']()
|
||||||
|
ct.save()
|
||||||
|
tgt_cred = Credential.objects.create(
|
||||||
|
name='Test Machine Credential',
|
||||||
|
organization=organization,
|
||||||
|
credential_type=ct,
|
||||||
|
inputs={'username': 'bob'}
|
||||||
|
)
|
||||||
|
|
||||||
|
result = run_module('tower_credential_input_source', dict(
|
||||||
|
source_credential=source_cred_centrify_secret.name,
|
||||||
|
target_credential=tgt_cred.name,
|
||||||
|
input_field_name='password',
|
||||||
|
metadata={"system-name": "systemname", "account-name": "accountname"},
|
||||||
|
state='present'
|
||||||
|
), admin_user)
|
||||||
|
|
||||||
|
assert not result.get('failed', False), result.get('msg', result)
|
||||||
|
assert result.get('changed'), result
|
||||||
|
assert CredentialInputSource.objects.count() == 1
|
||||||
|
cis = CredentialInputSource.objects.first()
|
||||||
|
|
||||||
|
assert cis.metadata['system-name'] == "systemname"
|
||||||
|
assert cis.metadata['account-name'] == "accountname"
|
||||||
|
assert cis.source_credential.name == source_cred_centrify_secret.name
|
||||||
|
assert cis.target_credential.name == tgt_cred.name
|
||||||
|
assert cis.input_field_name == 'password'
|
||||||
|
assert result['id'] == cis.pk
|
||||||
|
|||||||
3
setup.py
3
setup.py
@@ -130,7 +130,8 @@ setup(
|
|||||||
'hashivault_kv = awx.main.credential_plugins.hashivault:hashivault_kv_plugin',
|
'hashivault_kv = awx.main.credential_plugins.hashivault:hashivault_kv_plugin',
|
||||||
'hashivault_ssh = awx.main.credential_plugins.hashivault:hashivault_ssh_plugin',
|
'hashivault_ssh = awx.main.credential_plugins.hashivault:hashivault_ssh_plugin',
|
||||||
'azure_kv = awx.main.credential_plugins.azure_kv:azure_keyvault_plugin',
|
'azure_kv = awx.main.credential_plugins.azure_kv:azure_keyvault_plugin',
|
||||||
'aim = awx.main.credential_plugins.aim:aim_plugin'
|
'aim = awx.main.credential_plugins.aim:aim_plugin',
|
||||||
|
'centrify_vault_kv = awx.main.credential_plugins.centrify_vault:centrify_plugin'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
data_files = proc_data_files([
|
data_files = proc_data_files([
|
||||||
|
|||||||
Reference in New Issue
Block a user