azure integration. methods to authenticate and set/get value in keyvault

This commit is contained in:
Philip Kalinsky 2020-01-20 14:17:01 -05:00 committed by tomdds
parent 67842748b8
commit becc3630c2
3 changed files with 152 additions and 71 deletions

View File

@ -35,6 +35,7 @@ azure-mgmt-resource = "*"
transitions = "*"
azure-mgmt-consumption = "*"
adal = "*"
azure-identity = "*"
[dev-packages]
bandit = "*"

73
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "a127b88e6c64842786f1868cb93bb1cdc828aa78040ea8ba4079bb3de0316dab"
"sha256": "3760f0b1df1156211d671afa2eb417b7bf980aa33d2f74d390e8eed6a3ce8c8b"
},
"pipfile-spec": 6,
"requires": {
@ -45,6 +45,13 @@
],
"version": "==1.1.24"
},
"azure-core": {
"hashes": [
"sha256:b8ccbd901d085048e4e3e72627b066923c5bd3780e4c43cf9cf9948aee9bdf9e",
"sha256:e2cd99f0c0aef12c168d498cb5bc47a3a45c8ab08112183e3ec97e4dcb33ceb9"
],
"version": "==1.2.1"
},
"azure-graphrbac": {
"hashes": [
"sha256:53e98ae2ca7c19b349e9e9bb1b6a824aeae8dcfcbe17190d20fe69c0f185b2e2",
@ -53,6 +60,14 @@
"index": "pypi",
"version": "==0.61.1"
},
"azure-identity": {
"hashes": [
"sha256:4ce65058461c277991763ed3f121efc6b9eb9c2edefb62c414dfa85c814690d3",
"sha256:b32acd1cdb6202bfe10d9a0858dc463d8960295da70ae18097eb3b85ab12cb91"
],
"index": "pypi",
"version": "==1.2.0"
},
"azure-mgmt-authorization": {
"hashes": [
"sha256:31e875a34ac2c5d6fefe77b4a8079a8b2bdbe9edb957e47e8b44222fb212d6a7",
@ -354,6 +369,20 @@
],
"version": "==8.1.0"
},
"msal": {
"hashes": [
"sha256:c944b833bf686dfbc973e9affdef94b77e616cb52ab397e76cde82e26b8a3373",
"sha256:ecbe3f5ac77facad16abf08eb9d8562af3bc7184be5d4d90c9ef4db5bde26340"
],
"version": "==1.0.0"
},
"msal-extensions": {
"hashes": [
"sha256:59e171a9a4baacdbf001c66915efeaef372fb424421f1a4397115a3ddd6205dc",
"sha256:c5a32b8e1dce1c67733dcdf8aa8bebcff5ab123e779ef7bc14e416bd0da90037"
],
"version": "==0.1.3"
},
"msrest": {
"hashes": [
"sha256:56b8b5b4556fb2a92cac640df267d560889bdc9e2921187772d4691d97bc4e8d",
@ -388,6 +417,13 @@
"index": "pypi",
"version": "==2.0.5"
},
"portalocker": {
"hashes": [
"sha256:6f57aabb25ba176462dc7c63b86c42ad6a9b5bd3d679a9d776d0536bfb803d54",
"sha256:dac62e53e5670cb40d2ee4cdc785e6b829665932c3ee75307ad677cf5f7d2e9f"
],
"version": "==1.5.2"
},
"psycopg2-binary": {
"hashes": [
"sha256:040234f8a4a8dfd692662a8308d78f63f31a97e1c42d2480e5e6810c48966a29",
@ -453,6 +489,9 @@
"version": "==1.3"
},
"pyjwt": {
"extras": [
"crypto"
],
"hashes": [
"sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e",
"sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96"
@ -538,10 +577,10 @@
},
"six": {
"hashes": [
"sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd",
"sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66"
"sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a",
"sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"
],
"version": "==1.13.0"
"version": "==1.14.0"
},
"sqlalchemy": {
"hashes": [
@ -618,10 +657,10 @@
},
"zipp": {
"hashes": [
"sha256:8dda78f06bd1674bd8720df8a50bb47b6e1233c503a4eed8e7810686bde37656",
"sha256:d38fbe01bbf7a3593a32bc35a9c4453c32bc42b98c377f9bff7e9f8da157786c"
"sha256:57147f6b0403b59f33fd357f169f860e031303415aeb7d04ede4839d23905ab8",
"sha256:7ae5ccaca427bafa9760ac3cd8f8c244bfc259794b5b6bb9db4dda2241575d09"
],
"version": "==1.0.0"
"version": "==2.0.0"
}
},
"develop": {
@ -632,14 +671,6 @@
],
"version": "==1.4.3"
},
"appnope": {
"hashes": [
"sha256:5b26757dc6f79a3b7dc9fab95359328d5747fcb2409d331ea66d0272b90ab2a0",
"sha256:8b995ffe925347a2138d7ac0fe77155e4311a0ea6d6da4f5128fe4b3cbe5ed71"
],
"markers": "sys_platform == 'darwin'",
"version": "==0.1.0"
},
"argh": {
"hashes": [
"sha256:a9b3aaa1904eeb78e32394cd46c6f37ac0fb4af6dc488daa58971bdc7d7fcaf3",
@ -1210,10 +1241,10 @@
},
"six": {
"hashes": [
"sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd",
"sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66"
"sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a",
"sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"
],
"version": "==1.13.0"
"version": "==1.14.0"
},
"smmap2": {
"hashes": [
@ -1328,10 +1359,10 @@
},
"zipp": {
"hashes": [
"sha256:8dda78f06bd1674bd8720df8a50bb47b6e1233c503a4eed8e7810686bde37656",
"sha256:d38fbe01bbf7a3593a32bc35a9c4453c32bc42b98c377f9bff7e9f8da157786c"
"sha256:57147f6b0403b59f33fd357f169f860e031303415aeb7d04ede4839d23905ab8",
"sha256:7ae5ccaca427bafa9760ac3cd8f8c244bfc259794b5b6bb9db4dda2241575d09"
],
"version": "==1.0.0"
"version": "==2.0.0"
}
}
}

View File

@ -207,9 +207,10 @@ class TenantCSPResult(AliasModel):
return {
"tenant_admin_username": self.tenant_admin_username,
"tenant_admin_password": self.tenant_admin_password,
"tenant_id": self.tenant_id
"tenant_id": self.tenant_id,
}
class BillingProfileAddress(AliasModel):
company_name: str
address_line_1: str
@ -248,9 +249,7 @@ class BillingProfileCSPPayload(BaseCSPPayload):
return v or []
class Config:
fields = {
"billing_profile_display_name": "displayName"
}
fields = {"billing_profile_display_name": "displayName"}
class BillingProfileCreateCSPResult(AliasModel):
@ -258,7 +257,10 @@ class BillingProfileCreateCSPResult(AliasModel):
retry_after: int
class Config:
fields = {"billing_profile_validate_url": "Location", "retry_after": "Retry-After"}
fields = {
"billing_profile_validate_url": "Location",
"retry_after": "Retry-After",
}
class BillingProfileVerifyCSPPayload(BaseCSPPayload):
@ -279,9 +281,7 @@ class BillingProfileProperties(AliasModel):
invoice_sections: List[BillingInvoiceSection]
class Config:
fields = {
"billing_profile_display_name": "displayName"
}
fields = {"billing_profile_display_name": "displayName"}
class BillingProfileCSPResult(AliasModel):
@ -314,20 +314,27 @@ class BillingProfileTenantAccessCSPResult(AliasModel):
"billing_role_assignment_name": "name",
}
class TaskOrderBillingCSPPayload(BaseCSPPayload):
billing_account_name: str
billing_profile_name: str
class EnableTaskOrderBillingCSPResult(AliasModel):
task_order_billing_validation_url: str
retry_after: int
class Config:
fields = {"task_order_billing_validation_url": "Location", "retry_after": "Retry-After"}
fields = {
"task_order_billing_validation_url": "Location",
"retry_after": "Retry-After",
}
class TaskOrderBillingCSPResult(BaseCSPPayload):
task_order_billing_validation_url: str
class BillingProfileEnabledPlanDetails(AliasModel):
enabled_azure_plans: List[Dict]
@ -344,6 +351,7 @@ class TaskOrderBillingCSPResult(AliasModel):
"billing_profile_enabled_plan_details": "properties",
}
class ReportCLINCSPPayload(BaseCSPPayload):
amount: float
start_date: str
@ -353,6 +361,7 @@ class ReportCLINCSPPayload(BaseCSPPayload):
billing_account_name: str
billing_profile_name: str
class ReportCLINCSPResult(AliasModel):
reported_clin_name: str
@ -361,7 +370,16 @@ class ReportCLINCSPResult(AliasModel):
"reported_clin_name": "name",
}
class CloudProviderInterface:
def set_secret(secret_key: str, secret_value: str):
raise NotImplementedError()
def get_secret(secret_key: str, secret_value: str):
raise NotImplementedError()
def root_creds(self) -> Dict:
raise NotImplementedError()
@ -563,7 +581,7 @@ class MockCloudProvider(CloudProviderInterface):
"user_id": response["userId"],
"user_object_id": response["objectId"],
"tenant_admin_username": "test",
"tenant_admin_password": "test"
"tenant_admin_password": "test",
}
def create_billing_profile(self, payload):
@ -608,33 +626,33 @@ class MockCloudProvider(CloudProviderInterface):
response = {"id": "string"}
# return {"billing_profile_id": response["id"]}
return {
'id': '/providers/Microsoft.Billing/billingAccounts/7c89b735-b22b-55c0-ab5a-c624843e8bf6:de4416ce-acc6-44b1-8122-c87c4e903c91_2019-05-31/billingProfiles/KQWI-W2SU-BG7-TGB',
'name': 'KQWI-W2SU-BG7-TGB',
'properties': {
'address': {
'addressLine1': '123 S Broad Street, Suite 2400',
'city': 'Philadelphia',
'companyName': 'Promptworks',
'country': 'US',
'postalCode': '19109',
'region': 'PA'
"id": "/providers/Microsoft.Billing/billingAccounts/7c89b735-b22b-55c0-ab5a-c624843e8bf6:de4416ce-acc6-44b1-8122-c87c4e903c91_2019-05-31/billingProfiles/KQWI-W2SU-BG7-TGB",
"name": "KQWI-W2SU-BG7-TGB",
"properties": {
"address": {
"addressLine1": "123 S Broad Street, Suite 2400",
"city": "Philadelphia",
"companyName": "Promptworks",
"country": "US",
"postalCode": "19109",
"region": "PA",
},
'currency': 'USD',
'displayName': 'Test Billing Profile',
'enabledAzurePlans': [],
'hasReadAccess': True,
'invoiceDay': 5,
'invoiceEmailOptIn': False,
'invoiceSections': [{
'id': '/providers/Microsoft.Billing/billingAccounts/7c89b735-b22b-55c0-ab5a-c624843e8bf6:de4416ce-acc6-44b1-8122-c87c4e903c91_2019-05-31/billingProfiles/KQWI-W2SU-BG7-TGB/invoiceSections/CHCO-BAAR-PJA-TGB',
'name': 'CHCO-BAAR-PJA-TGB',
'properties': {
'displayName': 'Test Billing Profile'
},
'type': 'Microsoft.Billing/billingAccounts/billingProfiles/invoiceSections'
}]
"currency": "USD",
"displayName": "Test Billing Profile",
"enabledAzurePlans": [],
"hasReadAccess": True,
"invoiceDay": 5,
"invoiceEmailOptIn": False,
"invoiceSections": [
{
"id": "/providers/Microsoft.Billing/billingAccounts/7c89b735-b22b-55c0-ab5a-c624843e8bf6:de4416ce-acc6-44b1-8122-c87c4e903c91_2019-05-31/billingProfiles/KQWI-W2SU-BG7-TGB/invoiceSections/CHCO-BAAR-PJA-TGB",
"name": "CHCO-BAAR-PJA-TGB",
"properties": {"displayName": "Test Billing Profile"},
"type": "Microsoft.Billing/billingAccounts/billingProfiles/invoiceSections",
}
],
},
'type': 'Microsoft.Billing/billingAccounts/billingProfiles'
"type": "Microsoft.Billing/billingAccounts/billingProfiles",
}
def create_billing_profile_tenant_access(self, payload):
@ -651,9 +669,9 @@ class MockCloudProvider(CloudProviderInterface):
"principalId": "0a5f4926-e3ee-4f47-a6e3-8b0a30a40e3d",
"principalTenantId": "60ff9d34-82bf-4f21-b565-308ef0533435",
"roleDefinitionId": "/providers/Microsoft.Billing/billingAccounts/7c89b735-b22b-55c0-ab5a-c624843e8bf6:de4416ce-acc6-44b1-8122-c87c4e903c91_2019-05-31/billingProfiles/KQWI-W2SU-BG7-TGB/billingRoleDefinitions/40000000-aaaa-bbbb-cccc-100000000000",
"scope": "/providers/Microsoft.Billing/billingAccounts/7c89b735-b22b-55c0-ab5a-c624843e8bf6:de4416ce-acc6-44b1-8122-c87c4e903c91_2019-05-31/billingProfiles/KQWI-W2SU-BG7-TGB"
"scope": "/providers/Microsoft.Billing/billingAccounts/7c89b735-b22b-55c0-ab5a-c624843e8bf6:de4416ce-acc6-44b1-8122-c87c4e903c91_2019-05-31/billingProfiles/KQWI-W2SU-BG7-TGB",
},
"type": "Microsoft.Billing/billingRoleAssignments"
"type": "Microsoft.Billing/billingRoleAssignments",
}
def create_or_update_user(self, auth_credentials, user_info, csp_role_id):
@ -735,6 +753,9 @@ class AzureSDKProvider(object):
from azure.mgmt import subscription, authorization
import azure.graphrbac as graphrbac
import azure.common.credentials as credentials
import azure.identity as identity
from azure.keyvault import secrets import secrets
from msrestazure.azure_cloud import AZURE_PUBLIC_CLOUD
import adal
import requests
@ -744,6 +765,8 @@ class AzureSDKProvider(object):
self.adal = adal
self.graphrbac = graphrbac
self.credentials = credentials
self.identity = identity
self.secrets = secrets
self.requests = requests
# may change to a JEDI cloud
self.cloud = AZURE_PUBLIC_CLOUD
@ -756,12 +779,29 @@ class AzureCloudProvider(CloudProviderInterface):
self.client_id = config["AZURE_CLIENT_ID"]
self.secret_key = config["AZURE_SECRET_KEY"]
self.tenant_id = config["AZURE_TENANT_ID"]
self.vault_url = config["AZURE_VAULT_URL"]
if azure_sdk_provider is None:
self.sdk = AzureSDKProvider()
else:
self.sdk = azure_sdk_provider
def set_secret(secret_key, secret_value):
credential = self._get_client_secret_credential_obj()
secret_client = self.secrets.SecretClient(
vault_url=self.vault_url,
credential=credential,
)
return secret_client.set_secret(secret_key, secret_value)
def get_secret(secret_key)
credential = self._get_client_secret_credential_obj()
secret_client = self.secrets.SecretClient(
vault_url=self.vault_url,
credential=credential,
)
return secret_client.get_secret(secret_key).value
def create_environment(
self, auth_credentials: Dict, user: User, environment: Environment
):
@ -856,7 +896,7 @@ class AzureCloudProvider(CloudProviderInterface):
headers=create_tenant_headers,
)
print('create tenant result')
print("create tenant result")
print(result.json())
if result.status_code == 200:
@ -907,7 +947,9 @@ class AzureCloudProvider(CloudProviderInterface):
"Authorization": f"Bearer {sp_token}",
}
result = self.sdk.requests.get(payload.billing_profile_validate_url, headers=auth_header)
result = self.sdk.requests.get(
payload.billing_profile_validate_url, headers=auth_header
)
if result.status_code == 202:
# 202 has location/retry after headers
@ -917,7 +959,9 @@ class AzureCloudProvider(CloudProviderInterface):
else:
return self._error(result.json())
def create_billing_profile_tenant_access(self, payload: BillingProfileTenantAccessCSPPayload):
def create_billing_profile_tenant_access(
self, payload: BillingProfileTenantAccessCSPPayload
):
sp_token = self._get_sp_token(payload.creds)
request_body = {
"properties": {
@ -945,11 +989,7 @@ class AzureCloudProvider(CloudProviderInterface):
{
"op": "replace",
"path": "/enabledAzurePlans",
"value": [
{
"skuId": "0001"
}
]
"value": [{"skuId": "0001"}],
}
]
@ -959,7 +999,9 @@ class AzureCloudProvider(CloudProviderInterface):
url = f"https://management.azure.com/providers/Microsoft.Billing/billingAccounts/{payload.billing_account_name}/billingProfiles/{payload.billing_profile_name}?api-version=2019-10-01-preview"
result = self.sdk.requests.patch(url, headers=request_headers, json=request_body)
result = self.sdk.requests.patch(
url, headers=request_headers, json=request_body
)
if result.status_code == 202:
# 202 has location/retry after headers
@ -969,7 +1011,7 @@ class AzureCloudProvider(CloudProviderInterface):
else:
return self._error(result.json())
def validate_task_order_billing_enabled(self, payload: VerifyTaskOrderBillingCSPPayload):
def validate_task_order_billing_enabled(self, payload: TaskOrderBillingCSPPayload):
sp_token = self._get_sp_token(payload.creds)
if sp_token is None:
raise AuthenticationException(
@ -980,7 +1022,9 @@ class AzureCloudProvider(CloudProviderInterface):
"Authorization": f"Bearer {sp_token}",
}
result = self.sdk.requests.get(payload.task_order_billing_validation_url, headers=auth_header)
result = self.sdk.requests.get(
payload.task_order_billing_validation_url, headers=auth_header
)
if result.status_code == 202:
# 202 has location/retry after headers
@ -1001,7 +1045,7 @@ class AzureCloudProvider(CloudProviderInterface):
"properties": {
"amount": payload.amount,
"startDate": payload.start_date,
"endDate": payload.end_date
"endDate": payload.end_date,
}
}
@ -1125,7 +1169,6 @@ class AzureCloudProvider(CloudProviderInterface):
return token_response.get("accessToken", None)
def _get_credential_obj(self, creds, resource=None):
return self.sdk.credentials.ServicePrincipalCredentials(
client_id=creds.get("client_id"),
secret=creds.get("secret_key"),
@ -1133,6 +1176,12 @@ class AzureCloudProvider(CloudProviderInterface):
resource=resource,
cloud_environment=self.sdk.cloud,
)
def _get_client_secret_credential_obj():
return self.sdk.identity.ClientSecretCredential(
tenant_id=creds.get("tenant_id"),
client_id =creds.get("client_id"),
client_secret = creds.get("secret_key"),
)
def _make_tenant_admin_cred_obj(self, username, password):
return self.sdk.credentials.UserPassCredentials(username, password)