import json import logging import threading import urllib3 import os import re import sys import random import time import boto3 from botocore.exceptions import ClientError # from botocore.config import Config # _rand = random.randint(10, 2400) service_name = "license-manager" ps_client = boto3.client( service_name, region_name='us-east-1') org_client = boto3.client('organizations') s3client = boto3.client('s3') iam_client = boto3.client('iam') ssmclient = boto3.client('ssm') sc_client = boto3.client('servicecatalog') http = urllib3.PoolManager() logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) #== def get_ssm_para(name): response = ssmclient.get_parameter(Name=name) return response['Parameter']['Value'] def orglistroots(event): _ret = org_client.list_roots() _id = _ret['Roots'][0]['Id'] _r_arr=[] _ret2 = org_client.list_organizational_units_for_parent( ParentId=_id) for _o in _ret2['OrganizationalUnits']: #print(_o) if _o['Name'].find('Core') > -1 : mess='not the core' else: _n = f"{_o['Name']}" _r_arr.append(_n) _r_arr.sort() ### _ret = org_client.list_roots() _id = _ret['Roots'][0]['Id'] _ret2 = org_client.list_organizational_units_for_parent( ParentId=_id) _bigret=[] for _curorg in _r_arr: for _o in _ret2['OrganizationalUnits']: if _o['Name'] == _curorg : ParentId = _o['Id'] _accts = org_client.list_accounts_for_parent(ParentId=ParentId) _acctCount = len(_accts['Accounts']) _lbuf = f"{_curorg}_Accounts({_acctCount})" _bigret.append(_lbuf) return(_bigret) def put_ssm_para(kdict): pres = ssmclient.put_parameter( Name=kdict['Name'], Description=kdict['Description'], Value=kdict['Value'], Type=kdict['Type'], Overwrite=True) def gen_surl(bucketname, keyname): url = s3client.generate_presigned_url(ClientMethod='get_object', Params={ 'Bucket': bucketname, 'Key': keyname}) return url def b_putpriv_v1(bucket, key, acl): srep = s3client.put_object_acl(ACL=acl, Bucket=bucket, Key=key) return srep def b_putpriv(bucket, key, body,type): srep = s3client.put_object( ACL='private', Body=body, Bucket=bucket, Key=key, ContentType=type,) print(srep) return srep def b_get_obj(bucket, bkey): object = s3client.get_object(Bucket=bucket, Key=bkey) return(object['Body'].read().decode('utf-8')) def cr_acct_alowedvalues(event): _ar = [] try: _accts = org_client.list_accounts() for _act in _accts['Accounts']: ok_to_add =1 if _act['Name'].find('Audit') > -1: ok_to_add = 0 if _act['Name'].find('Log archive') > -1: ok_to_add = 0 if ok_to_add == 1: _b = f"{_act['Name']}_{_act['Id']}" _ar.append(_b) _ar.sort() except Exception as e: _ar.append('Error_gettingAccounts ' + str(e)) return _ar def ps_CreateGrant(GrantName, LicenseArn, Principals, HomeRegion, AllowedOperations): ClientToken = f"ctoken{_rand}" _ret = ps_client.create_grant(ClientToken=ClientToken, GrantName=GrantName, LicenseArn=LicenseArn, Principals=Principals, HomeRegion=HomeRegion, AllowedOperations=AllowedOperations) return _ret def ps_list_distributed_grants(): _ret = ps_client.list_distributed_grants() return _ret def ps_list_received_licenses(): _ret = {} try: _ret = ps_client.list_received_licenses() # print(_ret) _reta = [] for _Licenses in _ret['Licenses']: if _Licenses['Status'] != "DELETED": _lname = _Licenses['LicenseName'] _grantarn = '' if 'LicenseMetadata' in _Licenses: for lm in _Licenses['LicenseMetadata']: if lm['Name'] == 'grantArn': _grantarn = lm['Value'] _gr = {'Name': _lname, 'grantArn': _grantarn, 'LicenseArn': _Licenses['LicenseArn']} _reta.append(_gr) if len(_reta) == 0: _gr = {'Name': 'none', 'grantArn': 'None','LicenseArn': 'none:error:error:error:error:error:error:error'} _reta.append(_gr) _ret['LicenseInfo'] = _reta except Exception as e: print('Error cgetting lic ' + str(e)) _darray = [] _gr = {'Name': 'ErrorGettingLic', 'grantArn': 'error', 'LicenseArn': 'error:error:error:error:error:error:error:error'} _darray.append(_gr) _ret['LicenseInfo'] = _darray return _ret def ps_list_received_grants(): _ret = ps_client.list_received_grants() return _ret def ps_list_licenses(): _ret = ps_client.list_licenses() return _ret def update_sc_product(event, licinfo): sc_mgtentitlementProduct = b_get_obj( event['ResourceProperties']['HoldingBucket'], 'content/mgtentitlement/sc_mgtentitlement_sc_product_new.json') sc_json = json.loads(sc_mgtentitlementProduct) _licarray = [] for _license in licinfo['LicenseInfo']: _liccode = _license['LicenseArn'].split(':')[6] licname = f"{_license['Name']}_{_liccode}" _licarray.append(licname) _licarray.sort() _parameter_01 = {"Type": "String", "Description": "Select the account which will receive the grant. To deploy to accounts in an OrganizationalUnits select[02-Deploy_To_OrganizationalUnits]", "AllowedValues": licinfo['AccountId']} _parameter_02 = {"Type": "String", "Description": "Select the License to create the grant for", "AllowedValues": _licarray} _parameter_03 = {"Type": "String", "Description": "Select the OrganizationalUnits whose accounts will receive the grants", "AllowedValues": licinfo['OrganizationalUnits']} sc_json['Parameters']['RecipientAccount'] = _parameter_01 sc_json['Parameters']['License'] = _parameter_02 sc_json['Parameters']['OrganizationalUnits'] = _parameter_03 sc_json_sc_key = f'content/mgtentitlement/sc_mgtentitlement_sc_product_new.json' b_putpriv(event['ResourceProperties']['HoldingBucket'], sc_json_sc_key, json.dumps(sc_json, indent=4),'text/json') sc_json_sc_s3loc = 'https://%s.s3.%s.amazonaws.com/%s' % ( event['ResourceProperties']['HoldingBucket'], os.environ['AWS_REGION'], sc_json_sc_key) return sc_json_sc_s3loc def make_sc_product(event, licinfo): sc_mgtentitlementProduct = b_get_obj( event['ResourceProperties']['HoldingBucket'], 'content/mgtentitlement/sc_mgtentitlement_sc_product.json') sc_json = json.loads(sc_mgtentitlementProduct) _licarray = [] for _license in licinfo['LicenseInfo']: _liccode = _license['LicenseArn'].split(':')[6] licname = f"{_license['Name']}_{_liccode}" _licarray.append(licname) _parameter_01 = {"Type": "String", "Description": "Select the account which will receive the grant. To deploy to accounts in an OrganizationalUnits select[02-Deploy_To_OrganizationalUnits]", "AllowedValues": licinfo['AccountId']} _parameter_02 = {"Type": "String", "Description": "Select the License to create the grant for", "AllowedValues": _licarray} _parameter_03 = {"Type": "String", "Description": "Select the OrganizationalUnits whose accounts will receive the grants", "AllowedValues": licinfo['OrganizationalUnits']} sc_json['Parameters']['RecipientAccount'] = _parameter_01 sc_json['Parameters']['License'] = _parameter_02 sc_json['Parameters']['OrganizationalUnits'] = _parameter_03 sc_json['Resources']['SCPoleStarMgtRun']['Properties']['mgtentitlement_role'] = event['ResourceProperties']['mgtentitlement_role'] sc_json['Resources']['SCPoleStarMgtRun']['Properties']['HoldingBucket'] = event['ResourceProperties']['HoldingBucket'] sc_json['Resources']['SCPoleStarMgtRun']['Properties']['ServiceToken'] = event['ResourceProperties']['ServiceToken'] #sc_json['Resources']['SCPoleStarMgtRun']['Properties']['ReportsBucket'] = event['ResourceProperties']['ReportsBucket'] sc_json_sc_key = f'content/mgtentitlement/sc_mgtentitlement_sc_product_new.json' b_putpriv(event['ResourceProperties']['HoldingBucket'], sc_json_sc_key, json.dumps(sc_json, indent=4),'text/json') sc_json_sc_s3loc = 'https://%s.s3.%s.amazonaws.com/%s' % ( event['ResourceProperties']['HoldingBucket'], os.environ['AWS_REGION'], sc_json_sc_key) return sc_json_sc_s3loc def ps_list_grant_rec(): _ret = ps_client.list_received_grants() _reta = [] for _grant in _ret['Grants']: if _grant['GrantStatus'] != "DELETED": _gr = {'GrantName': _grant['GrantName'], 'GrantArn': _grant['GrantArn'], 'GrantStatus': _grant['GrantStatus'], 'LicenseArn': _grant['LicenseArn'], 'Version': _grant['LicenseArn']} _reta.append(_gr) return _reta def ps_accept_grant(GrantArn): # #my_config = Config( region_name = 'us-east-1',signature_version = 'v4',retries = {'max_attempts': 10,'mode': 'standard'}) #lm_client = boto3.client('license-manager', config=my_config) _ret = ps_client.accept_grant(GrantArn) print(_ret) return _ret def ps_CreateGrant(GrantName, LicenseArn, Principals, HomeRegion, AllowedOperations): _rand = random.randint(130, 2400) ClientToken = f"ctoken{_rand}" _ret = ps_client.create_grant(ClientToken=ClientToken, GrantName=GrantName, LicenseArn=LicenseArn, Principals=Principals, HomeRegion=HomeRegion, AllowedOperations=AllowedOperations) return _ret def create_a_grant(ginfo): _gret = {} try: LicenseArn = ginfo['LicenseArn'] Principals = ginfo['Principals'] LicenseName = ginfo['LicenseName'] GrantName = f"SC_Grant-{_rand}-{LicenseName}" HomeRegion = 'us-east-1' # print(LicenseArn) # print("arn:aws:license-manager::294406891311:license:l-57151b41aff8479ca5a6594d58cf0178") AllowedOperations = ["CheckoutLicense", "CheckInLicense", "ExtendConsumptionLicense", "ListPurchasedLicenses"] _gret = ps_CreateGrant( GrantName, LicenseArn, Principals, HomeRegion, AllowedOperations) print(_gret) except Exception as e: print('Error creating grant ' + str(e)) _gret['Status'] = 'Error'+str(e) _gret['GrantArn'] = 'None' return _gret def cfnresponse(event, context, responseStatus, responseData, physicalResourceId=None, noEcho=False): responseBody = {} responseBody['Status'] = responseStatus responseBody['Reason'] = 'See the details in CloudWatch Log Stream: ' + \ context.log_stream_name responseBody['PhysicalResourceId'] = physicalResourceId or context.log_stream_name responseBody['StackId'] = event['StackId'] responseBody['RequestId'] = event['RequestId'] responseBody['LogicalResourceId'] = event['LogicalResourceId'] responseBody['NoEcho'] = noEcho responseBody['Data'] = responseData json_responseBody = json.dumps(responseBody) headers = {'content-type': '', 'content-length': str(len(json_responseBody))} print("Response body:\n" + json_responseBody) try: response = http.request( 'PUT', event['ResponseURL'], body=json_responseBody.encode('utf-8'), headers=headers) logger.debug('Status code: ' + response.reason) except Exception as e: logger.error( 'cfnresponse(..) failed executing requests.put(..): ' + str(e)) def timeout(event, context): logging.error( 'Execution is about to time out, sending failure response to CloudFormation') cfnresponse(event, context, 'FAILED') def look_for_mgtentitlement_role(iam_client, event): rolename = event['ResourceProperties']['mgtentitlement_role'] _ret = {'found': "no", 'portPrincipal': ''} _rret = iam_client.list_roles() for _role in _rret['Roles']: if _role['RoleName'] == rolename: _ret['found'] = "yes" if _role['RoleName'].find('AWSReservedSSO_AWSAdministratorAccess') > -1: _ret['portPrincipal'] = _role['RoleName'] return _ret def assume_role(account): assumedRoleObject = {} sts_client = boto3.client('sts') role_arn = 'arn:aws:iam::' + \ account['AccountId'] + ':role/' + \ account['adminRole'] try: assumedRoleObject = sts_client.assume_role( RoleArn=role_arn, RoleSessionName="NewAccountRole" ) except Exception as e: logger.warning(e) assumedRoleObject['status'] = str(e) return assumedRoleObject def account_b_accept(targetAcctGrant, event): stack_desc = '' _rand = random.randint(10, 44200) acct_b = assume_role(targetAcctGrant) ACCESS_KEY = acct_b['Credentials']['AccessKeyId'] SECRET_KEY = acct_b['Credentials']['SecretAccessKey'] SESSION_TOKEN = acct_b['Credentials']['SessionToken'] GrantArn = targetAcctGrant['GrantArn'] ps_b_accpt_client = boto3.client( 'license-manager', region_name='us-east-1', aws_access_key_id=ACCESS_KEY, aws_secret_access_key=SECRET_KEY, aws_session_token=SESSION_TOKEN, ) ps_b_client = boto3.client( 'license-manager', aws_access_key_id=ACCESS_KEY, aws_secret_access_key=SECRET_KEY, aws_session_token=SESSION_TOKEN, ) # act_b_iam_client = boto3.client( 'iam', aws_access_key_id=ACCESS_KEY, aws_secret_access_key=SECRET_KEY, aws_session_token=SESSION_TOKEN, ) lookforroleacctb = look_for_mgtentitlement_role( act_b_iam_client, event) print(json.dumps(lookforroleacctb)) if lookforroleacctb['found'] == "yes": sc_json_sc_key = f'content/mgtentitlement/mgtentitlement_role_setup_blank.json' sc_mgtentitlement_role = 'https://%s.s3.%s.amazonaws.com/%s' % (event['ResourceProperties']['HoldingBucket'], os.environ['AWS_REGION'], sc_json_sc_key) else: sc_json_sc_key = f'content/mgtentitlement/mgtentitlement_role_setup.json' sc_mgtentitlement_role = 'https://%s.s3.%s.amazonaws.com/%s' % ( event['ResourceProperties']['HoldingBucket'], os.environ['AWS_REGION'], sc_json_sc_key) sc_mgtentitlement_role_surl = gen_surl( event['ResourceProperties']['HoldingBucket'], sc_json_sc_key) event['ResourceProperties']['taraccount'] = targetAcctGrant['AccountId'] event['ResourceProperties']['StackName'] = f'mgtentitlementtRoleSetup{_rand}' event['ResourceProperties']['StackRegion'] = os.environ['AWS_REGION'] event['ResourceProperties']['TemplateURL'] = sc_mgtentitlement_role_surl stack_desc = deploy_cloudformation( event, acct_b['Credentials'], "mgtentitlement setup") time.sleep(10) _grantret = ps_b_accpt_client.accept_grant(GrantArn=GrantArn) print('Accepted') time.sleep(10) _ngrantinfo = ps_b_client.get_grant(GrantArn=GrantArn) print('GetGrantAfterAccepted') SourceVersion = _ngrantinfo['Grant']['Version'] ClientToken = f"ctoken{_rand}" _grantActivate = ps_b_client.create_grant_version( GrantArn=GrantArn, ClientToken=ClientToken, SourceVersion=SourceVersion, Status='ACTIVE') time.sleep(5) newGrantInfo = ps_b_client.get_grant(GrantArn=GrantArn) # build TargetAccount SC Env. sc_json_tar_sc_key = f'content/mgtentitlement/sc_mgtentitlement_setup.json' TarActSCtemplate = json.loads(b_get_obj( event['ResourceProperties']['HoldingBucket'], sc_json_tar_sc_key)) TarActSCtemplate['Outputs'] = {} SCenduser = TarActSCtemplate['Parameters']['SCenduser'] SCenduser['Default'] = f"role/{lookforroleacctb['portPrincipal']}" TarActSCtemplate['Parameters'] = {} TarActSCtemplate['Parameters']['SCenduser'] = SCenduser resource_portfolio = TarActSCtemplate['Resources']['SCPortfolio'] resource_sc_product = TarActSCtemplate['Resources']['SCproductmEntitlements'] resource_prod_associate = TarActSCtemplate[ 'Resources']['ProdAssociateSCproductmEntitlements'] resource_SCPortPrincipal = TarActSCtemplate['Resources']['SCPortPrincipal'] resource_sc_product['DependsOn'] = [] prod_name = event['ResourceProperties']['License'].split( '_l-')[0] resource_sc_product['Properties']['Description'] = f"AWS Marketplace-{prod_name}" resource_sc_product['Properties']['Name'] = f"AWS Marketplace-{prod_name}" # cleanprod_name = re.sub('[^-a-zA-Z0-9]','',prod_name) resource_portfolio['Properties']['DisplayName'] = f'AWS Marketplace Products {cleanprod_name}' #fix ImageId for EC2 ec2_template = json.loads(b_get_obj(event['ResourceProperties']['HoldingBucket'], 'content/mgtentitlement/sc_mgtentitlement_ec2_product.json')) ec2_template['Parameters']['ImageId']['Default'] = event['ResourceProperties']['ImageId'] ec2_template_key= f'content/mgtentitlement/sc_mgtentitlement_ec2_product{_rand}.json' b_putpriv(event['ResourceProperties']['HoldingBucket'],ec2_template_key,json.dumps(ec2_template, indent=2),'text/json') resource_sc_product['Properties']['ProvisioningArtifactParameters'][0]['Info']['LoadTemplateFromURL'] = gen_surl( event['ResourceProperties']['HoldingBucket'], ec2_template_key) TarActSCtemplate['Resources'] = {} TarActSCtemplate['Resources']['SCPortfolio'] = resource_portfolio TarActSCtemplate['Resources']['SCproductmEntitlements'] = resource_sc_product TarActSCtemplate['Resources']['ProdAssociateSCproductmEntitlements'] = resource_prod_associate if lookforroleacctb['portPrincipal'] != '': TarActSCtemplate['Resources']['SCPortPrincipal'] = resource_SCPortPrincipal TarActSCtemplate['Description'] = f"AWS Marketplace-MgtEntitlements-{prod_name}" tarsckey = f"content/mgtentitlement/sc_mgtentitlement_sc_env{_rand}_{targetAcctGrant['AccountId']}.json" b_putpriv(event['ResourceProperties']['HoldingBucket'], tarsckey, json.dumps(TarActSCtemplate, indent=2),'text/json') sc_mgtentitlement_role_surl = gen_surl( event['ResourceProperties']['HoldingBucket'], tarsckey) #cleanprod_name = prod_name.replace(' ','') #cleanprod_name = cleanprod_name.replace('(','') #cleanprod_name = cleanprod_name.replace(')','') event['ResourceProperties']['taraccount'] = targetAcctGrant['AccountId'] event['ResourceProperties']['StackName'] = f'mgtentitle-{cleanprod_name}-{_rand}' event['ResourceProperties']['StackRegion'] = os.environ['AWS_REGION'] event['ResourceProperties']['TemplateURL'] = sc_mgtentitlement_role_surl stack_desc = deploy_cloudformation( event, acct_b['Credentials'], "mgtentitlementTarget setup") return newGrantInfo def deploy_cloudformation(event, acct_b, application): logger.debug("Deploying Resources") stack_name = event['ResourceProperties']['StackName'] stack_region = event['ResourceProperties']['StackRegion'] TemplateURL = event['ResourceProperties']['TemplateURL'] taraccount = event['ResourceProperties']['taraccount'] datestamp = time.strftime("%d/%m/%Y") client = boto3.client('cloudformation', aws_access_key_id=acct_b['AccessKeyId'], aws_secret_access_key=acct_b['SecretAccessKey'], aws_session_token=acct_b['SessionToken'], region_name=stack_region) logger.info("Creating stack " + stack_name + " in " + taraccount) logger.info( "Creating stack TemplateURL[" + TemplateURL + "]") creating_stack = True while creating_stack is True: try: creating_stack = False create_stack_response = client.create_stack( StackName=stack_name, TemplateURL=TemplateURL, Parameters=[], NotificationARNs=[], Capabilities=[ 'CAPABILITY_NAMED_IAM' ], OnFailure='ROLLBACK', Tags=[ { 'Key': 'ManagedResource', 'Value': 'True' }, { 'Key': 'DeployDate', 'Value': datestamp } ] ) except ClientError as e: to_raise = ['AlreadyExistsException', 'LimitExceededException', 'InsufficientCapabilitiesException'] logger.error(e.response) if e.response['Error']['Code'] in to_raise: client.delete_stack(StackName=stack_name) logger.error(e) raise creating_stack = True logger.warning(e) logger.warning("Retrying...") time.sleep(10) except Exception as e: logger.error(e) stack_building = True logger.info("Stack creation in process...") # logger.info(create_stack_response) while stack_building is True: event_list = client.describe_stack_events( StackName=stack_name).get("StackEvents") stack_event = event_list[0] if (stack_event.get('ResourceType') == 'AWS::CloudFormation::Stack' and stack_event.get('ResourceStatus') == 'CREATE_COMPLETE'): stack_building = False logger.info("Stack construction complete.") elif (stack_event.get('ResourceType') == 'AWS::CloudFormation::Stack' and stack_event.get('ResourceStatus') == 'ROLLBACK_COMPLETE'): client.delete_stack(StackName=stack_name) stack_building = False logger.error("Stack construction failed.") sys.exit(1) else: logger.info(stack_event) logger.info("Stack building . . .") time.sleep(10) stack = client.describe_stacks(StackName=stack_name) return stack def sc_deactivat_ver(_newversion, _prodinfo): for _product in _prodinfo: if _newversion != _product['Name']: response = sc_client.update_provisioning_artifact(AcceptLanguage='en', ProductId=_product[ 'ProductId'], ProvisioningArtifactId=_product['ProvisioningArtifactId'], Active=False, Guidance='DEPRECATED') return 0 def sc_create_pa(ProductId, version, description, template): _rand = random.randint(323, 24200) IdempotencyToken = "tok%s" % _rand print(template + IdempotencyToken) rep = sc_client.create_provisioning_artifact(AcceptLanguage='en', ProductId=ProductId, Parameters={ 'Name': version, 'Description': description, 'Info': { "LoadTemplateFromURL": template }, 'Type': 'CLOUD_FORMATION_TEMPLATE', 'DisableTemplateValidation': True }, IdempotencyToken=IdempotencyToken ) return rep def sc_describe_product(name): rep = {} try: rep = sc_client.describe_product_as_admin( AcceptLanguage='en', Name=name) except Exception as e: e = str(e) print(e) if e.find('ResourceNotFoundException') > -1: print(name + ' not found') return 'not found' ProductId = rep['ProductViewDetail']['ProductViewSummary']['ProductId'] # print(rep) # print(rep['ProvisioningArtifactSummaries']) _ret = [] for _prodversion in rep['ProvisioningArtifactSummaries']: _version = {'ProductId': ProductId, 'ProvisioningArtifactId': _prodversion[ 'Id'], 'Name': _prodversion['Name'], 'Description': _prodversion['Description']} _ret.append(_version) return _ret def mgt_ent_sc_updateProduct(_sc_productname, template): _prodinfo = sc_describe_product(_sc_productname) # return _prodinfo _versions = len(_prodinfo) + 1 ProductId = _prodinfo[0]['ProductId'] version = 'Latest %s.0' % _versions description = 'Decription %s' % version pa_rep = sc_create_pa( ProductId, version, description, template) _ret = {'ProductId': ProductId, 'version': version, 'ProvisioningArtifactId': pa_rep['ProvisioningArtifactDetail']['Id']} # Deactivate old version _prodinfo = sc_describe_product(_sc_productname) sc_deactivat_ver(version, _prodinfo) return _ret def ps_list_distributed_grants_4_lic(LicenseArn,PrincipalARN,filter): Filters=[ { 'Name': 'GranteePrincipalArn', 'Values': [ PrincipalARN ] }, { 'Name': 'GrantStatus', 'Values': [ 'ACTIVE' ] }, { 'Name': 'LicenseARN', 'Values': [ LicenseArn ] } ] _rret=[] if filter =='yes': _ret = ps_client.list_distributed_grants(Filters=Filters)['Grants'] else: _ret = ps_client.list_distributed_grants()['Grants'] return _ret def ListAccounts(orgname): _ar = [] try: _ret = org_client.list_roots() _id = _ret['Roots'][0]['Id'] _ret2 = org_client.list_organizational_units_for_parent( ParentId=_id) for _o in _ret2['OrganizationalUnits']: if _o['Name'] == orgname : ParentId = _o['Id'] _accts = org_client.list_accounts_for_parent(ParentId=ParentId) for _act in _accts['Accounts']: _b = f"{_act['Name']}_{_act['Id']}_{_act['Status']}" _ar.append(_b) _ar.sort() except Exception as e: _ar.append('Error_gettingAccounts ' + str(e)) return _ar def deployGrantsToOu(event): _ret={} _lgrants =[] _lic_a = event['ResourceProperties']['License'].split('_l-')[1] _lic_Name = event['ResourceProperties']['License'].split('_l-')[0] _ou = event['ResourceProperties']['OrganizationalUnits'].split('_')[0] _actdeplist=[] rr=[] _ret['message'] = f"Deploying {_lic_Name} grants to {_ou}" OuTargetAccounts = ListAccounts(_ou) print(len(OuTargetAccounts)) print(OuTargetAccounts) if len(OuTargetAccounts) > 0: for targetAccount in OuTargetAccounts: _recipient_acount = targetAccount.split('_')[1] _Principals = f"arn:aws:iam::{_recipient_acount}:root" _licarn = f"arn:aws:license-manager::294406891311:license:l-{_lic_a}" #look for accounts that already have the lic-grant _accountswgrants = ps_list_distributed_grants_4_lic(_licarn,_Principals,'yes') #return _accountswgrants _lgrants.append(_accountswgrants) lrs = {'_recipient_acount':targetAccount,'accouts':_accountswgrants} rr.append(lrs) if len(_accountswgrants) == 0: _grantinfo = {'LicenseArn': _licarn, "Principals": [_Principals], 'LicenseName': _lic_Name,'recipient_acount':_recipient_acount} _actdeplist.append(_grantinfo) _ret['GrantInventory'] = _accountswgrants _ret['_actdeplist'] = _actdeplist #return _actdeplist for _gtarget in _actdeplist: _lic_Name = _gtarget['LicenseName'] _recipient_acount = _gtarget['recipient_acount'] _cret = create_a_grant(_gtarget) TargetAccount = {'AccountId': _recipient_acount,'adminRole': 'AWSControlTowerExecution', 'GrantArn': _cret['GrantArn']} _ret['GrantAcceptInfo'] = account_b_accept(TargetAccount, event) else: _ret['message'] = f"No accounts in {_ou}" return _ret def deployGrantsToAccount(event): _ret={} _lgrants =[] _lic_a = event['ResourceProperties']['License'].split('_l-')[1] _lic_Name = event['ResourceProperties']['License'].split('_l-')[0] _recipient_acount = event['ResourceProperties']['RecipientAccount'].split('_')[1] _Principals = f"arn:aws:iam::{_recipient_acount}:root" _licarn = f"arn:aws:license-manager::294406891311:license:l-{_lic_a}" _accountswgrants = ps_list_distributed_grants_4_lic(_licarn,_Principals,'yes') if len(_accountswgrants) == 0: _grantinfo = {'LicenseArn': _licarn, "Principals": [_Principals], 'LicenseName': _lic_Name,'recipient_acount':_recipient_acount} _cret = create_a_grant(_grantinfo) TargetAccount = {'AccountId': _recipient_acount,'adminRole': 'AWSControlTowerExecution', 'GrantArn': _cret['GrantArn']} time.sleep(7) _ret['GrantAcceptInfo'] = account_b_accept(TargetAccount, event) else: _ret['message'] = f"{_recipient_acount} already has {_lic_Name}, check the report" return _ret def generate_report (event): _ret={} _lgrants =[] _lic_a = event['ResourceProperties']['License'].split('_l-')[1] _lic_Name = event['ResourceProperties']['License'].split('_l-')[0] _ou = event['ResourceProperties']['OrganizationalUnits'] _recipient_acount ='blank' _Principals = f"arn:aws:iam::{_recipient_acount}:root" _licarn = f"arn:aws:license-manager::294406891311:license:l-{_lic_a}" _ret['GrantInventory'] = ps_list_distributed_grants_4_lic(_licarn,_Principals,'no') #return _ret style = """ """ grants_json = _ret rows = "" for i in grants_json["GrantInventory"]: rGrantName = i['GrantName'].split('-')[2] rows += f" {rGrantName}{re.search('[0-9]+',i['GranteePrincipalArn']).group(0)}{i['HomeRegion']}{i['GrantStatus']} {i['LicenseArn']}" table = f"{rows}
NameAWS AccountRegionStatusLicenseArn
" html = f"{style}{table}" #grantinventory = _ret['GrantInventory'] #Reporting rBUCKET = event['ResourceProperties']['HoldingBucket'] region = os.environ['AWS_REGION'] OUTPUT_KEY = f"content/mgtentitlement/report/grants.json" #b_putpriv(BUCKET, INPUT_KEY, grantinventory, 'text/json') #OUTPUT_KEY = f"reports/grants.html" b_putpriv(rBUCKET, OUTPUT_KEY, html,'text/html') _ret = gen_surl(rBUCKET, OUTPUT_KEY) return _ret def lambda_handler(event, context): #return generate_report (event) print(json.dumps(event)) timer = threading.Timer((context.get_remaining_time_in_millis() / 1000.00) - 0.5, timeout, args=[event, context]) timer.start() status = 'SUCCESS' _ret = {} _ret['report']='none' _ret['message']='none' try: if event['RequestType'] == 'Create': if event['ResourceProperties']['action'] == "create_setup": _licDet = {} # Check if you are in amaster account _orgunits = orglistroots(event) _accounts = cr_acct_alowedvalues(event) if _accounts[0].find('Error_gettingAccounts') > -1: sc_json_sc_key = f'content/mgtentitlement/mgtentitlement_role_setup_blank.json' sc_mgtentitlement_product = 'https://%s.s3.%s.amazonaws.com/%s' % ( event['ResourceProperties']['HoldingBucket'], os.environ['AWS_REGION'], sc_json_sc_key) _ret['sc_mgtentitlementProdTemplateUrl'] = sc_mgtentitlement_product else: _accounts.append('01-Update_Accounts-And-Subscriptions') _accounts.append('02-Deploy_To_OrganizationalUnits') _accounts.sort() _licDet['LicenseInfo'] = ps_list_received_licenses()[ 'LicenseInfo'] _licDet['AccountId'] = _accounts _licDet['OrganizationalUnits'] = _orgunits _ret['sc_mentitlementsProdTemplateUrl'] = make_sc_product( event, _licDet) if look_for_mgtentitlement_role(iam_client, event)['found'] == "yes": sc_json_sc_key = f'content/mgtentitlement/mgtentitlement_role_setup_blank.json' sc_mgtentitlement_role = 'https://%s.s3.%s.amazonaws.com/%s' % ( event['ResourceProperties']['HoldingBucket'], os.environ['AWS_REGION'], sc_json_sc_key) else: sc_json_sc_key = f'content/mgtentitlement/mgtentitlement_role_setup.json' sc_mgtentitlement_role = 'https://%s.s3.%s.amazonaws.com/%s' % ( event['ResourceProperties']['HoldingBucket'], os.environ['AWS_REGION'], sc_json_sc_key) _ret['sc_mgtentitlement_role'] = sc_mgtentitlement_role if event['ResourceProperties']['action'] == "create_grant": if event['ResourceProperties']['RecipientAccount'] == '01-Update_Accounts-And-Subscriptions': _licDet = {} _accounts = cr_acct_alowedvalues(event) _orgunits = orglistroots(event) _accounts.append( '01-Update_Accounts-And-Subscriptions') _accounts.append('02-Deploy_To_OrganizationalUnits') _accounts.sort() _licDet['LicenseInfo'] = ps_list_received_licenses()['LicenseInfo'] _licDet['AccountId'] = _accounts _licDet['OrganizationalUnits'] = _orgunits _ret['sc_mentitlementsProdTemplateUrl'] = update_sc_product( event, _licDet) _ret['message'] = 'Updating product with new MP Lic and accounts' template = _ret['sc_mentitlementsProdTemplateUrl'] _sc_productname = 'AWS MP License Management -ManageEntitlements' time.sleep(4) _ret['UpdateMessage'] = mgt_ent_sc_updateProduct( _sc_productname, template) _ret['message'] = _ret['message'] + ' ' + _ret['UpdateMessage']['version'] else: event['ResourceProperties']['mgtentitlement_role'] = "AWSServiceRoleForAWSLicenseManagerRole" event['ResourceProperties']['HoldingBucket'] = event['ResourceProperties']['HoldingBucket'] if event['ResourceProperties']['RecipientAccount'] == "02-Deploy_To_OrganizationalUnits": _ret = deployGrantsToOu(event) else: _ret = deployGrantsToAccount(event) _ret['report']=generate_report (event) if event['RequestType'] == 'Delete': if event['ResourceProperties']['action'] == "create_setup": _licDet = {} if event['ResourceProperties']['action'] == "create_grant": _lic_a = event['ResourceProperties']['License'].split( '_l-')[1] _lic_Name = event['ResourceProperties']['License'].split( '_l-')[0] _recipient_acount = event['ResourceProperties']['RecipientAccount'].split('_')[ 1] _licarn = f"arn:aws:license-manager::294406891311:license:l-{_lic_a}" _Principals = f"arn:aws:iam::{_recipient_acount}:root" _grantinfo = {'LicenseArn': _licarn, "Principals": [ _Principals], 'LicenseName': _lic_Name} _ret['message'] = f"My action will be to Delete a grant with lic-{_lic_Name} for account {_recipient_acount}" except Exception as e: print(e) logging.error('Exception: %s' % e, exc_info=True) status = FAILED finally: timer.cancel() cfnresponse(event, context, status, _ret) return _ret