--- AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: this code deploys 3 Lambdas for creating SSM activation, Adding Tags to Managed instances and then also a function to check if a workspace exits as a managed instance # More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst Globals: Function: Timeout: 120 MemorySize: 128 Parameters: SsmRegion: Type: String Description: The region you want to have Managed instances in SSM This is where you would deploy this stack. Default: 'us-east-1' LdapServerIp: Type: String Description: IP Address of the DC that can be used to get group details Default: '' SubnetId: Type: String Description: Subnet ID of the AD connector. Default: '' SgGroup: Type: String Description: Security Group of the AD connector This is needed for the function to connect to AD and get groups Default: '' BaseDn: Type: String Description: Domian base DN eg = DC=microsoft,dC=com Default: '' Domain: Type: String Description: domain name in the format conteso.com Default: '' User: Type: String Description: AD username for ldap queries just only the username without any quotations Default: '' ADPasswordSecretName: Type: String Description: The name of the secret that has the password for the AD user stored Default: 'adpasswd' DynamoTable: Type: String Description: The name of the secret that has the password for the AD user stored Default: 'WS_SSM_tag_data' Resources: WsFindAndGetActivatefn: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Properties: PackageType: Image Environment: Variables: stackregion: !Ref SsmRegion instancerole: !Ref WsMiRole Policies: - Statement: - Sid: DSdescribePolicy Effect: Allow Action: - ds:DescribeDirectories Resource: '*' - Sid: WSdescribePolicy Effect: Allow Action: - workspaces:DescribeWorkspaces Resource: '*' - Sid: SSMpolicies Effect: Allow Action: - ssm:CreateActivation - ssm:DeleteAssociation - ssm:DeregisterManagedInstance - ssm:DescribeEffectiveInstanceAssociations - ssm:GetInventory Resource: '*' - Sid: ssmpassrole Effect: Allow Action: - iam:PassRole - iam:GetRole Resource: !GetAtt WsMiRole.Arn Events: wsfindandactivateapi: Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api Properties: Path: /getactivation Method: get RequestParameters: - method.request.querystring.hostname - method.request.querystring.wsregion - method.request.querystring.username - method.request.querystring.ipadd Metadata: Dockerfile: Dockerfile DockerContext: ./findandactivate DockerTag: python3.9-v1 CheckmiStatus: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Properties: PackageType: Image Environment: Variables: stackregion: !Ref SsmRegion Policies: - Statement: - Sid: ssmgetconnectionstat Effect: Allow Action: - ssm:GetConnectionStatus - ssm:GetInventory Resource: '*' Events: checkmistatus: Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api Properties: Path: /checkmistat Method: get RequestParameters: - method.request.querystring.wsid - method.request.querystring.hostname Metadata: Dockerfile: Dockerfile DockerContext: ./checkmistatus DockerTag: python3.9-v1 WsAddTagFunction: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Properties: PackageType: Image Environment: Variables: stackregion: !Ref SsmRegion Policies: - Statement: - Sid: SSMpolicies Effect: Allow Action: - ssm:AddTagsToResource Resource: '*' Events: wsaddtag: Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api Properties: Path: /wsmiaddtag Method: get RequestParameters: - method.request.querystring.wsid - method.request.querystring.miid - method.request.querystring.hostname - method.request.querystring.username - method.request.querystring.directoryid - method.request.querystring.wsregion - method.request.querystring.OS Metadata: Dockerfile: Dockerfile DockerContext: ./wsaddtag DockerTag: python3.9-v1 AddGroupTagfn: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Properties: Environment: Variables: stackregion: !Ref SsmRegion ldapserv: !Ref LdapServerIp basedn: !Ref BaseDn domain: !Ref Domain user: !Ref User VpcConfig: SecurityGroupIds: - !Ref SgGroup SubnetIds: - !Ref SubnetId Policies: - Statement: - Sid: ssmperms Effect: Allow Action: - ssm:ListTagsForResource - ssm:AddTagsToResource - ssm:RemoveTagsFromResource Resource: '*' - Sid: secrets Effect: Allow Action: - secretsmanager:GetSecretValue Resource: !Sub 'arn:${AWS::Partition}:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:adpasswd*' PackageType: Image Events: addadtags: Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api Properties: Path: /ad Method: get RequestParameters: - method.request.querystring.miid - method.request.querystring.username Metadata: Dockerfile: Dockerfile DockerContext: ./ad DockerTag: python3.9-v1 WsMiRole: Type: 'AWS::IAM::Role' Properties: ManagedPolicyArns: - !Sub 'arn:${AWS::Partition}:iam::aws:policy/AmazonSSMManagedInstanceCore' AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - ssm.amazonaws.com Action: - 'sts:AssumeRole' Policies: - PolicyName: 'ssmrole' PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - ssmmessages:CreateControlChannel - ssmmessages:CreateDataChannel - ssmmessages:OpenControlChannel - ssmmessages:OpenDataChannel Resource: - '*' - Effect: Allow Action: - kms:Decrypt Resource: - !Sub 'arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:alias/ssm' WsDeleteEvent: Type: AWS::Events::Rule Properties: Description: this event is triggered when WS is terminated Name: WSDeleteEventrule EventPattern: { "source": [ "aws.workspaces" ], "detail-type": [ "AWS API Call via CloudTrail" ], "detail": { "eventSource": [ "workspaces.amazonaws.com" ], "eventName": [ "TerminateWorkspaces", "" ] } } State: ENABLED Targets: - Arn: Fn::GetAtt: - "DeleteMIwhenWSDeleted" - "Arn" Id: "DeleteMIwhenWSDeleted" SendMiToSqs: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Properties: MemorySize: 128 Environment: Variables: stackregion: !Ref SsmRegion SQS: !Ref MySqsQueue Policies: - Statement: - Sid: ssmperms Effect: Allow Action: - ssm:ListTagsForResource - ssm:AddTagsToResource - ssm:RemoveTagsFromResource - ssm:DescribeInstanceInformation Resource: '*' PackageType: Image Architectures: - x86_64 Metadata: Dockerfile: Dockerfile DockerContext: ./sendmitosqs DockerTag: python3.9-v1 CronforTagRenewal: Type: AWS::Events::Rule Properties: Description: This is the CW event to trigger refresh of AD group tags for workspaces Name: WsTagRenwalCronRule ScheduleExpression: "rate(4 hours)" State: ENABLED Targets: - Arn: Fn::GetAtt: - "SendMiToSqs" - "Arn" Id: "SendMiToSqs" PermForCronforTagRenewalEventToInvokeLambda: Type: AWS::Lambda::Permission Properties: FunctionName: Ref: 'SendMiToSqs' Action: 'lambda:InvokeFunction' Principal: 'events.amazonaws.com' SourceArn: Fn::GetAtt: - 'CronforTagRenewal' - 'Arn' DeleteMIwhenWSDeleted: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Properties: Environment: Variables: stackregion: !Ref SsmRegion Policies: - Statement: - Sid: ssm Effect: Allow Action: - ssm:DescribeInstanceInformation - ssm:DeregisterManagedInstance Resource: '*' PackageType: Image Metadata: Dockerfile: Dockerfile DockerContext: ./cleanoldmi DockerTag: python3.9-v1 PermForWSDeleteEventToInvokeLambda: Type: AWS::Lambda::Permission Properties: FunctionName: Ref: 'DeleteMIwhenWSDeleted' Action: 'lambda:InvokeFunction' Principal: 'events.amazonaws.com' SourceArn: Fn::GetAtt: - 'WsDeleteEvent' - 'Arn' TaggerSQSworker: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Properties: MemorySize: 256 Timeout: 60 Environment: Variables: stackregion: !Ref SsmRegion ldapserv: !Ref LdapServerIp basedn: !Ref BaseDn domain: !Ref Domain user: !Ref User secretname: !Ref ADPasswordSecretName ddbtable: !Ref DynamoTable VpcConfig: SecurityGroupIds: - !Ref SgGroup SubnetIds: - !Ref SubnetId Policies: - Statement: - Sid: ssmperms Effect: Allow Action: - ssm:ListTagsForResource - ssm:AddTagsToResource - ssm:RemoveTagsFromResource - ssm:DescribeInstanceInformation Resource: '*' - Sid: secrets Effect: Allow Action: - secretsmanager:GetSecretValue Resource: !Sub 'arn:${AWS::Partition}:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:adpasswd*' PackageType: Image Architectures: - x86_64 Events: MySQSEvent: Type: SQS Properties: Queue: !GetAtt MySqsQueue.Arn BatchSize: 2 Metadata: Dockerfile: Dockerfile DockerContext: ./TaggerSQSworker DockerTag: python3.9-v1 MySqsQueue: Type: AWS::SQS::Queue Properties: VisibilityTimeout: 120 MessageRetentionPeriod: 300 MySqsQueuePolicy: Type: AWS::SQS::QueuePolicy Properties: Queues: - !Ref MySqsQueue PolicyDocument: Id: MyQueuePolicy Version: '2012-10-17' Statement: - Sid: workerperms Action: - "SQS:SendMessage" - "SQS:ReceiveMessage" - "SQS:DeleteMessage" Effect: "Allow" Resource: !GetAtt [MySqsQueue, Arn] Principal: AWS: - !GetAtt SendMiToSqsRole.Arn - !GetAtt TaggerSQSworkerRole.Arn Outputs: # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function # Find out more about other implicit resources you can reference within SAM # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api workspacessminstallapi: Description: "API Gateway endpoint Base URL" Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/" wsfindandgetactivatefuctionarn: Description: "get WSID search create activation Function ARN" Value: !GetAtt WsFindAndGetActivatefn.Arn checkmistatusfunctionarn: Description: "check managed instance status Function ARN" Value: !GetAtt CheckmiStatus.Arn wsaddtagfunctionarn: Description: "Add tags to managed instance Function ARN" Value: !GetAtt WsAddTagFunction.Arn addgrouptagfunctionarn: Description: "Add AD Group tags to managed instance Function ARN" Value: !GetAtt AddGroupTagfn.Arn managedinstancerolearn: Description: "Role assumed by the SSM managed instances" Value: !GetAtt WsMiRole.Arn DeleteMIwhenWSDeletedFnArn: Description: "Delete Managed Instance when workspace is deleted Function" Value: !GetAtt DeleteMIwhenWSDeleted.Arn SendMitoSqsFunction: Description: "Lambda function that gets Managed instance ID and sends to to SQS to be tagged" Value: !GetAtt SendMiToSqs.Arn TaggerSQSworkerFunction: Description: "Worker Lambda that consumes from SQS to tag AD groups for Workspaces" Value: !GetAtt TaggerSQSworker.Arn MySqsQueue: Description: "SQS queue that has is used for sending MI ID's to be tagged" Value: !GetAtt MySqsQueue.Arn