Draft of Azure create_environment
This commit is contained in:
parent
06239c94ba
commit
5cd20c650a
1
Pipfile
1
Pipfile
@ -25,6 +25,7 @@ PyYAML = "*"
|
||||
azure-storage = "*"
|
||||
azure-storage-common = "*"
|
||||
celery = "*"
|
||||
azure-mgmt-subscription = "*"
|
||||
|
||||
[dev-packages]
|
||||
bandit = "*"
|
||||
|
64
Pipfile.lock
generated
64
Pipfile.lock
generated
@ -1,21 +1,26 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "2f366c5a5f62ba5a451ca024759cc8cbf481a15e5198d73311fa9cf194d7f547"
|
||||
"sha256": "eca6e06b6a34bdba3872c595957d840da21f3e58cb41f3ec02b7c3a424a5e4c4"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.7.3"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
"sources": [{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}]
|
||||
},
|
||||
"default": {
|
||||
"adal": {
|
||||
"hashes": [
|
||||
"sha256:5a7f1e037c6290c6d7609cab33a9e5e988c2fbec5c51d1c4c649ee3faff37eaf",
|
||||
"sha256:fd17e5661f60634ddf96a569b95d34ccb8a98de60593d729c28bdcfe360eaad1"
|
||||
],
|
||||
"version": "==1.2.2"
|
||||
},
|
||||
"alembic": {
|
||||
"hashes": [
|
||||
"sha256:9f907d7e8b286a1cfb22db9084f9ce4fde7ad7956bb496dc7c952e10ac90e36a"
|
||||
@ -45,6 +50,14 @@
|
||||
],
|
||||
"version": "==1.1.23"
|
||||
},
|
||||
"azure-mgmt-subscription": {
|
||||
"hashes": [
|
||||
"sha256:504b4c42ba859070c3c50637ec07ca36aca600e613fcccaa398db22822fe21f1",
|
||||
"sha256:850f86de5078f61f3a9bd81cb2b938ea25ce9a266c9fe22c7fca94a2b5968c16"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.5.0"
|
||||
},
|
||||
"azure-nspkg": {
|
||||
"hashes": [
|
||||
"sha256:1d0bbb2157cf57b1bef6c8c8e5b41133957364456c43b0a43599890023cca0a8",
|
||||
@ -221,6 +234,13 @@
|
||||
],
|
||||
"version": "==0.23"
|
||||
},
|
||||
"isodate": {
|
||||
"hashes": [
|
||||
"sha256:2e364a3d5759479cdb2d37cce6b9376ea504db2ff90252a2e5b7cc89cc9ff2d8",
|
||||
"sha256:aa4d33c06640f5352aca96e4b81afd8ab3b47337cc12089822d6f322ac772c81"
|
||||
],
|
||||
"version": "==0.6.0"
|
||||
},
|
||||
"itsdangerous": {
|
||||
"hashes": [
|
||||
"sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19",
|
||||
@ -296,6 +316,27 @@
|
||||
],
|
||||
"version": "==7.2.0"
|
||||
},
|
||||
"msrest": {
|
||||
"hashes": [
|
||||
"sha256:56b8b5b4556fb2a92cac640df267d560889bdc9e2921187772d4691d97bc4e8d",
|
||||
"sha256:f5153bfe60ee757725816aedaa0772cbfe0bddb52cd2d6db4cb8b4c3c6c6f928"
|
||||
],
|
||||
"version": "==0.6.10"
|
||||
},
|
||||
"msrestazure": {
|
||||
"hashes": [
|
||||
"sha256:63db9f646fffc9244b332090e679d1e5f283ac491ee0cc321f5116f9450deb4a",
|
||||
"sha256:fecb6a72a3eb5483e4deff38210d26ae42d3f6d488a7a275bd2423a1a014b22c"
|
||||
],
|
||||
"version": "==0.6.2"
|
||||
},
|
||||
"oauthlib": {
|
||||
"hashes": [
|
||||
"sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889",
|
||||
"sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea"
|
||||
],
|
||||
"version": "==3.1.0"
|
||||
},
|
||||
"pendulum": {
|
||||
"hashes": [
|
||||
"sha256:1cde6e3c6310fb882c98f373795f807cb2bd6af01f34d2857e6e283b5ee91e09",
|
||||
@ -350,6 +391,13 @@
|
||||
],
|
||||
"version": "==2.19"
|
||||
},
|
||||
"pyjwt": {
|
||||
"hashes": [
|
||||
"sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e",
|
||||
"sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96"
|
||||
],
|
||||
"version": "==1.7.1"
|
||||
},
|
||||
"pyopenssl": {
|
||||
"hashes": [
|
||||
"sha256:aeca66338f6de19d1aa46ed634c3b9ae519a64b458f8468aec688e7e3c20f200",
|
||||
|
@ -383,3 +383,126 @@ class MockCloudProvider(CloudProviderInterface):
|
||||
self._delay(1, 5)
|
||||
if self._with_authorization and credentials != self._auth_credentials:
|
||||
raise self.AUTHENTICATION_EXCEPTION
|
||||
|
||||
|
||||
AZURE_ENVIRONMENT = "AZURE_PUBLIC_CLOUD" # TBD
|
||||
AZURE_SKU_ID = "?" # probably a static sku specific to ATAT/JEDI
|
||||
SUBSCRIPTION_ID_REGEX = re.compile(
|
||||
"subscriptions\/([0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})",
|
||||
re.I,
|
||||
)
|
||||
|
||||
class AzureCloudProvider(CloudProviderInterface):
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
|
||||
self.client_id = config["AZURE_CLIENT_ID"]
|
||||
self.secret_key = config["AZURE_SECRET_KEY"]
|
||||
self.tenant_id = config["AZURE_TENANT_ID"]
|
||||
|
||||
import azure.mgmt as mgmt
|
||||
import azure.graphrbac as graphrbac
|
||||
import azure.common.credentials as credentials
|
||||
|
||||
self.azure_mgmt = mgmt
|
||||
self.azure_graph = graphrbac
|
||||
self.azure_credentials = credentials
|
||||
|
||||
def root_creds(self):
|
||||
return {
|
||||
"client_id": self.client_id,
|
||||
"secret_key": self.secret_key,
|
||||
"tenant_id": self.tenant_id,
|
||||
}
|
||||
|
||||
def create_environment(
|
||||
self, auth_credentials: Dict, user: User, environment: Environment
|
||||
):
|
||||
credentials = self._get_credential_obj(self.root_creds())
|
||||
sub_client = self.azure_mgmt.subscription.SubscriptionClient(credentials)
|
||||
|
||||
display_name = (
|
||||
f"{environment.application.name}_{environment.name}_{environment.id}"
|
||||
) # proposed format
|
||||
|
||||
billing_profile_id = "?" # something chained from environment?
|
||||
sku_id = AZURE_SKU_ID
|
||||
body = self.azure_mgmt.subscription.models.ModernSubscriptionCreationParameters(
|
||||
display_name, billing_profile_id, sku_id
|
||||
)
|
||||
|
||||
# These 2 seem like something that might be worthwhile to allow tiebacks to
|
||||
# TOs filed for the environment
|
||||
billing_account_name = "?"
|
||||
invoice_section_name = "?"
|
||||
sub_creation_operation = sub_client.subscription_factory.create_subscription(
|
||||
billing_account_name, invoice_section_name, body
|
||||
)
|
||||
|
||||
# the resulting object from this process is a link to the new subscription
|
||||
# not a subscription model, so we'll have to unpack the ID
|
||||
new_sub = sub_creation_operation.result()
|
||||
|
||||
subscription_id = self._extract_subscription_id(new_sub.subscription_link)
|
||||
if subscription_id:
|
||||
return subscription_id
|
||||
else:
|
||||
# troublesome error, subscription should exist at this point
|
||||
# but we just don't have a valid ID
|
||||
pass
|
||||
|
||||
def create_atat_admin_user(
|
||||
self, auth_credentials: Dict, csp_environment_id: str
|
||||
) -> Dict:
|
||||
root_creds = self.root_creds()
|
||||
credentials = self._get_credential_obj(root_creds)
|
||||
|
||||
self.azure_mgmt.
|
||||
|
||||
sub_client = self.azure_mgmt.subscription.SubscriptionClient(credentials)
|
||||
subscription: self.azure_mgmt.subscription.models.Subscription = sub_client.subscriptions.get(
|
||||
csp_environment_id
|
||||
)
|
||||
|
||||
# how do we scope the graph client to the new subscription rather than
|
||||
# the cloud0 subscription? tenant id seems to be separate from subscription id
|
||||
graph_client = self.azure_graph.GraphRbacManagementClient(
|
||||
credentials, root_creds.get("tenant_id")
|
||||
app_create_param = self.azure_graph.models.ApplicationCreateParameters(
|
||||
display_name=app_display_name
|
||||
)
|
||||
app: self.azure_graph.models.Application = graph_client.applications.create(
|
||||
app_create_param
|
||||
)
|
||||
|
||||
self.azure_graph.models.
|
||||
|
||||
# create a new service principle for the new application, which should be scoped
|
||||
# to the new subscription
|
||||
app_id = app.app_id
|
||||
sp_create_params = self.azure_graph.models.ServicePrincipalCreateParameters(
|
||||
app_id=app_id, account_enabled=True
|
||||
)
|
||||
|
||||
service_principal = graph_client.service_principals.create(sp_create_params)
|
||||
|
||||
return {
|
||||
"csp_user_id": service_principal.object_id,
|
||||
"credentials": service_principal.password_credentials,
|
||||
}
|
||||
|
||||
def _extract_subscription_id(self, subscription_url):
|
||||
sub_id_match = SUBSCRIPTION_ID_REGEX.match(subscription_url)
|
||||
|
||||
if sub_id_match:
|
||||
return sub_id_match.group(1)
|
||||
|
||||
def _get_credential_obj(self, creds, resource="https://graph.windows.net"):
|
||||
return self.azure_credentials.ServicePrincipalCredentials(
|
||||
client_id=creds.get("client_id"),
|
||||
secret=creds.get("secret_key"),
|
||||
tenant=creds.get("tenant_id"),
|
||||
resource=resource,
|
||||
cloud_environment=AZURE_ENVIRONMENT,
|
||||
)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user