--- AWSTemplateFormatVersion: 2010-09-09 Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: "AWS Shield Advanced Subscription" Parameters: - AcknowledgeServiceTermsPricing - AcknowledgeServiceTermsDTO - AcknowledgeServiceTermsCommitment - AcknowledgeServiceTermsAutoRenew - AcknowledgeNoUnsubscribe - Label: default: "AWS Shield Advanced Proactive Engagement" Parameters: - EnabledProactiveEngagement - EmergencyContactEmail1 - EmergencyContactPhone1 - EmergencyContactNote1 - EmergencyContactEmail2 - EmergencyContactPhone2 - EmergencyContactNote2 - EmergencyContactEmail3 - EmergencyContactPhone3 - EmergencyContactNote3 - EmergencyContactEmail4 - EmergencyContactPhone4 - EmergencyContactNote4 - EmergencyContactEmail5 - EmergencyContactPhone5 - EmergencyContactNote5 - Label: default: "AWS Shield Advanced SRT Access" Parameters: - EnableSRTAccess - SRTAccessRoleName - SRTAccessRoleAction - SRTBuckets Parameters: AcknowledgeServiceTermsPricing: Type: String Default: False Description: Shield Advanced Service Term | Pricing | $3000 / month subscription fee for a consolidated billing family AllowedValues: - True - False AcknowledgeServiceTermsDTO: Type: String Default: False Description: Shield Advanced Service Term | Pricing | Data transfer out usage fees for all protected resources. AllowedValues: - True - False AcknowledgeServiceTermsCommitment: Type: String Default: False Description: Shield Advanced Term | Commitment | I am committing to a 12 month subscription. AllowedValues: - True - False AcknowledgeServiceTermsAutoRenew: Type: String Default: False Description: Shield Advanced Term | Auto renewal | Subscription will be auto-renewed after 12 months. However, I can opt out of renewal 30 days prior to the renewal date. AllowedValues: - True - False AcknowledgeNoUnsubscribe: Type: String Default: False Description: Shield Advanced does not un-subscribe on delete | Shield Advanced does not un-subscribe if you delete this stack/this resource. AllowedValues: - True - False EmergencyContactEmail1: Type: String Default: <na> AllowedPattern: ^\S+@\S+\.\S+$|\<na\> EmergencyContactEmail2: Type: String Default: <na> AllowedPattern: ^\S+@\S+\.\S+$|\<na\> EmergencyContactEmail3: Type: String Default: <na> AllowedPattern: ^\S+@\S+\.\S+$|\<na\> EmergencyContactEmail4: Type: String Default: <na> AllowedPattern: ^\S+@\S+\.\S+$|\<na\> EmergencyContactEmail5: Type: String Default: <na> AllowedPattern: ^\S+@\S+\.\S+$|\<na\> EmergencyContactPhone1: Type: String Default: <na> AllowedPattern: ^\+[0-9]{11}|\<na\> EmergencyContactPhone2: Type: String Default: <na> AllowedPattern: ^\+[0-9]{11}|\<na\> EmergencyContactPhone3: Type: String Default: <na> AllowedPattern: ^\+[0-9]{11}|\<na\> EmergencyContactPhone4: Type: String Default: <na> AllowedPattern: ^\+[0-9]{11}|\<na\> EmergencyContactPhone5: Type: String Default: <na> AllowedPattern: ^\+[0-9]{11}|\<na\> EmergencyContactNote1: Type: String Default: <na> AllowedPattern: ^[\w\s\.\-,:/()+@]*$|\<na\> EmergencyContactNote2: Type: String Default: <na> AllowedPattern: ^[\w\s\.\-,:/()+@]*$|\<na\> EmergencyContactNote3: Type: String Default: <na> AllowedPattern: ^[\w\s\.\-,:/()+@]*$|\<na\> EmergencyContactNote4: Type: String Default: <na> AllowedPattern: ^[\w\s\.\-,:/()+@]*$|\<na\> EmergencyContactNote5: Type: String Default: <na> AllowedPattern: ^[\w\s\.\-,:/()+@]*$|\<na\> EnabledProactiveEngagement: Type: String Default: False Description: Enable Proactive Engagement. Note you must also configure emergency contact(s) and health checks for protected resources for this feature to be effective AllowedValues: - True - False SRTBuckets: Type: CommaDelimitedList Default: <na> SRTAccessRoleName: Type: String Default: AWSSRTAccess SRTAccessRoleAction: Type: String Default: "CreateRole" AllowedValues: - "UseExisting" - "CreateRole" EnableSRTAccess: Type: String Default: False AllowedValues: - True - False Conditions: FirstEmergencyContact: !Not [ !Equals [!Ref EmergencyContactEmail1 , "<na>"]] SecondEmergencyContact: !Not [ !Equals [!Ref EmergencyContactEmail2 , "<na>"]] ThirdEmergencyContact: !Not [ !Equals [!Ref EmergencyContactEmail3 , "<na>"]] FourthEmergencyContact: !Not [ !Equals [!Ref EmergencyContactEmail4 , "<na>"]] FifthEmergencyContact: !Not [ !Equals [!Ref EmergencyContactEmail5 , "<na>"]] FirstEmergencyContactNote: !Not [ !Equals [!Ref EmergencyContactNote1 , "<na>"]] SecondEmergencyContactNote: !Not [ !Equals [!Ref EmergencyContactNote2 , "<na>"]] ThirdEmergencyContactNote: !Not [ !Equals [!Ref EmergencyContactNote3 , "<na>"]] FourthEmergencyContactNote: !Not [ !Equals [!Ref EmergencyContactNote4 , "<na>"]] FifthEmergencyContactNote: !Not [ !Equals [!Ref EmergencyContactNote5 , "<na>"]] EnableSRTAccessCondition: !Equals [!Ref "EnableSRTAccess", True] SRTCreateRoleCondition: !Equals [!Ref "SRTAccessRoleAction", "CreateRole"] SRTBucketsCondition: !Not [!Equals [ !Join [",",!Ref "SRTBuckets"], "<na>" ] ] ProactiveEngagementCondition: !Equals [ !Ref "EnabledProactiveEngagement",true] AcceptedShieldTerms: !And - Fn::Equals: - True - !Ref AcknowledgeServiceTermsPricing - Fn::Equals: - True - !Ref AcknowledgeServiceTermsDTO - Fn::Equals: - True - !Ref AcknowledgeServiceTermsCommitment - Fn::Equals: - True - !Ref AcknowledgeServiceTermsAutoRenew - Fn::Equals: - True - !Ref AcknowledgeNoUnsubscribe Resources: ConfigureShieldLambdaRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - 'sts:AssumeRole' Path: / ConfigureShieldLambdaPolicy: Type: 'AWS::IAM::Policy' Metadata: cfn_nag: rules_to_suppress: - id: W12 reason: "Wildcard IAM policy required, APIs do not support resource scoping" - id: W58 reason: "CFN Nag checks for managed policy, permissions granted inline" Properties: PolicyName: ConfigureShieldLambdaPolicy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - "logs:CreateLogGroup" - "logs:CreateLogStream" - "logs:PutLogEvents" Resource: "arn:aws:logs:*:*:*" - Sid: ShieldSubscription Effect: Allow Action: - shield:CreateSubscription - shield:UpdateSubscription - "xray:PutTraceSegments" - "xray:PutTelemetryRecords" Resource: "*" Roles: - !Ref ConfigureShieldLambdaRole SubscribeShieldAdvanced: Condition: AcceptedShieldTerms DependsOn: ConfigureShieldLambdaPolicy Type: Custom::SubscribeShieldAdvanced Properties: ServiceToken: !GetAtt ConfigureShieldLambda.Arn ConfigureShieldLambda: Type: AWS::Lambda::Function Metadata: cfn_nag: rules_to_suppress: - id: W58 reason: "Permissions granted, CFN_Nag not parsing correctly?" - id: W89 reason: "Not applicable for use case" - id: W92 reason: "Not applicable for use case" Properties: TracingConfig: Mode: Active Runtime: python3.9 Timeout: 15 Role: !GetAtt ConfigureShieldLambdaRole.Arn Handler: index.lambda_handler Code: ZipFile: | import boto3 import botocore try: import cfnresponse except: print ("no cfnresponse module") import logging logger = logging.getLogger('hc') logger.setLevel('DEBUG') shield_client = boto3.client('shield') def lambda_handler(event, context): logger.debug(event) responseData = {} if "RequestType" in event: if event['RequestType'] in ['Create','Update']: try: logger.debug("Start Create Subscription") shield_client.create_subscription() logger.info ("Shield Enabled!") responseData['Message'] = "Subscription Created" cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "SubscriptionCreated") return () except botocore.exceptions.ClientError as error: if error.response['Error']['Code'] == 'ResourceAlreadyExistsException': logger.info ("Subscription already active") responseData['Message'] = "Already Subscribed to Shield Advanced" cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "AlreadySubscribedOk") return else: logger.error(error.response['Error']) responseData['Message'] = error.response['Error'] cfnresponse.send(event, context, cfnresponse.FAILED, responseData, "SubscribeFailed") return () else: responseData['Message'] = "CFN Delete, no action taken" cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "CFNDeleteGracefulContinue") return() ProactiveEngagement: DeletionPolicy: Delete DependsOn: SubscribeShieldAdvanced Condition: ProactiveEngagementCondition Type: AWS::Shield::ProactiveEngagement Properties: ProactiveEngagementStatus: ENABLED EmergencyContactList: !If - FirstEmergencyContact - - !If - FirstEmergencyContact - EmailAddress: !Ref "EmergencyContactEmail1" ContactNotes: !If [FirstEmergencyContactNote, !Ref "EmergencyContactNote1", !Ref "AWS::NoValue"] PhoneNumber: !Ref "EmergencyContactPhone1" - !Ref "AWS::NoValue" - !If - SecondEmergencyContact - EmailAddress: !Ref "EmergencyContactEmail2" ContactNotes: !If [SecondEmergencyContactNote, !Ref "EmergencyContactNote2", !Ref "AWS::NoValue"] PhoneNumber: !Ref "EmergencyContactPhone2" - !Ref "AWS::NoValue" - !If - ThirdEmergencyContact - EmailAddress: !Ref "EmergencyContactEmail3" ContactNotes: !If [ThirdEmergencyContactNote, !Ref "EmergencyContactNote3", !Ref "AWS::NoValue"] PhoneNumber: !Ref "EmergencyContactPhone3" - !Ref "AWS::NoValue" - !If - FourthEmergencyContact - EmailAddress: !Ref "EmergencyContactEmail4" ContactNotes: !If [FourthEmergencyContactNote, !Ref "EmergencyContactNote4", !Ref "AWS::NoValue"] PhoneNumber: !Ref "EmergencyContactPhone4" - !Ref "AWS::NoValue" - !If - FifthEmergencyContact - EmailAddress: !Ref "EmergencyContactEmail5" ContactNotes: !If [FifthEmergencyContactNote, !Ref "EmergencyContactNote5", !Ref "AWS::NoValue"] PhoneNumber: !Ref "EmergencyContactPhone5" - !Ref "AWS::NoValue" - !Ref "AWS::NoValue" SRTAccess: Condition: EnableSRTAccessCondition DependsOn: SubscribeShieldAdvanced Type: AWS::Shield::DRTAccess Properties: LogBucketList: !If - SRTBucketsCondition - !Ref "SRTBuckets" - !Ref "AWS::NoValue" RoleArn: !If - SRTCreateRoleCondition - !GetAtt SRTAccessRole.Arn - !Sub "arn:aws:iam::${AWS::AccountId}:role/${SRTAccessRoleName}" SRTAccessRole: Condition: SRTCreateRoleCondition Type: AWS::IAM::Role Properties: RoleName: !Ref "SRTAccessRoleName" ManagedPolicyArns: - 'arn:aws:iam::aws:policy/service-role/AWSShieldDRTAccessPolicy' AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: - 'drt.shield.amazonaws.com' Action: - 'sts:AssumeRole'