AWSTemplateFormatVersion: '2010-09-09'
Description: 'Dynatrace Data Acquisition for AWS Organizations - Prerequisites Deployment (v1.0.1 2026-02-24 11:07)'

Metadata:
  Version:
    Number: v1.0.1
    ReleaseDate: 2026-02-24 11:07

  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: 'Dynatrace tokens'
        Parameters:
          - pDtApiToken
          - pDtIngestToken
      - Label:
          default: 'AWS Organizations'
        Parameters:
          - pManagementRegion
          - pAwsOrganizationId
      - Label:
          default: 'Deployment settings'
        Parameters:
          - pDynatraceUrl
          - pDeploymentInstanceIdentifier
    ParameterLabels:
      pDtApiToken:
        default: 'Dynatrace settings platform token'
      pDtIngestToken:
        default: 'Dynatrace log and event ingest token'
      pDynatraceUrl:
        default: 'Dynatrace environment url'
      pManagementRegion:
        default: 'AWS management region'
      pAwsOrganizationId:
        default: 'AWS Organization ID'
      pDeploymentInstanceIdentifier:
        default: 'Deployment instance identifier'

Parameters:
  pDynatraceUrl:
    Type: String
    AllowedPattern: '^https:\/\/.+[^\/]$'
  pManagementRegion:
    Type: String
    Description: 'AWS region where StackSets are deployed and managed from'
    AllowedValues: [ 'af-south-1', 'ap-east-1', 'ap-east-2', 'ap-northeast-1', 'ap-northeast-2', 'ap-northeast-3', 'ap-south-1', 'ap-south-2', 'ap-southeast-1', 'ap-southeast-2', 'ap-southeast-3', 'ap-southeast-4', 'ap-southeast-5', 'ap-southeast-6', 'ap-southeast-7', 'ca-central-1', 'ca-west-1', 'eu-central-1', 'eu-central-2', 'eu-north-1', 'eu-south-1', 'eu-south-2', 'eu-west-1', 'eu-west-2', 'eu-west-3', 'il-central-1', 'me-central-1', 'me-south-1', 'mx-central-1', 'sa-east-1', 'us-east-1', 'us-east-2', 'us-west-1', 'us-west-2' ]
    Default: 'us-east-1'
  pAwsOrganizationId:
    Type: String
    Description: 'AWS Organization identifier'
    AllowedPattern: '^o-[a-z0-9]{10,32}$'
  pDeploymentInstanceIdentifier:
    Type: String
    Description: '[Optional] Identifier of the Secrets Manager deployment where the Dynatrace Platform tokens were deployed (modify this parameter only if you are deploying multiple instances of the pre-requisites StackSets and you want to target a specific set of Secrets).'
    AllowedPattern: '(^$)|(^[a-zA-Z0-9]{1,64}$)'
  pDtApiToken:
    Type: String
    Description: 'Required scopes: settings:objects:write, extensions:configurations:write, extensions:configurations:read'
    AllowedPattern: '^dt0s16\.[A-Z0-9]{8}\.[A-Z0-9]{64}$'
    NoEcho: true
  pDtIngestToken:
    Type: String
    Description: 'Required scopes: data-acquisition:logs:ingest, data-acquisition:events:ingest'
    AllowedPattern: '(^$)|(^dt0s16\.[A-Z0-9]{8}\.[A-Z0-9]{64}$)'
    NoEcho: true

Conditions:
  cIsManagementRegion: !Equals
    - !Ref AWS::Region
    - !Ref pManagementRegion
  cDynatraceIngestTokenIsSet: !Not
    - !Equals
      - !Ref pDtIngestToken
      - ''

Resources:
  DynatraceKMSKey:
    Type: AWS::KMS::Key
    Properties:
      Description: !Sub 'KMS Key for encrypting Dynatrace tokens. Deployment: ${AWS::StackName}'
      KeyPolicy:
        Version: '2012-10-17'
        Id: AllowKMSPermissionsToOrgAccountsAndSecretsManager
        Statement:
          - Sid: Enable IAM User Permissions
            Effect: Allow
            Principal:
              AWS: !Sub 'arn:aws:iam::${AWS::AccountId}:root'
            Action: 'kms:*'
            Resource: '*'
          - Sid: Allow use of the key
            Effect: Allow
            Principal:
              AWS: '*'
            Action:
              - 'kms:Encrypt'
              - 'kms:Decrypt'
              - 'kms:DescribeKey'
              - 'kms:GenerateDataKey'
              - 'kms:GenerateDataKeyWithoutPlaintext'
            Resource: '*'
            Condition:
              StringEquals:
                'aws:PrincipalOrgID': !Ref pAwsOrganizationId
                'kms:ViaService': !Sub 'secretsmanager.${AWS::Region}.amazonaws.com'
      Tags:
        - Key: 'dt:CreatedBy'
          Value: 'Dynatrace'
        - Key: 'dt:EnvironmentID'
          Value: !Select [ 0, !Split [ ".", !Select [ 1, !Split [ "https://", !Ref pDynatraceUrl ] ] ] ]

  DynatraceKMSKeyAlias:
    Type: AWS::KMS::Alias
    Properties:
      TargetKeyId: !Ref DynatraceKMSKey
      AliasName: !Sub
        - 'alias/dynatrace/${DynatraceEnvironmentId}/keys/aws/${pAwsOrganizationId}/prerequisites/${pDeploymentInstanceIdentifier}'
        - DynatraceEnvironmentId: !Select [ 0, !Split [ ".", !Select [ 1, !Split [ "https://", !Ref pDynatraceUrl ] ] ] ]

  DynatraceSettingsTokenSecret:
    Type: AWS::SecretsManager::Secret
    Condition: cIsManagementRegion
    Properties:
      Name: !Sub
        - '/dynatrace/${DynatraceEnvironmentId}/tokens/aws/${pAwsOrganizationId}/integration/${pDeploymentInstanceIdentifier}'
        - DynatraceEnvironmentId: !Select [ 0, !Split [ ".", !Select [ 1, !Split [ "https://", !Ref pDynatraceUrl ] ] ] ]
      Description: 'Dynatrace Settings Platform token'
      SecretString:  !Sub '{"dynatrace_api_token": "${pDtApiToken}"}'
      KmsKeyId: !GetAtt DynatraceKMSKey.Arn
      Tags:
        - Key: 'dt:CreatedBy'
          Value: 'Dynatrace'
        - Key: 'dt:EnvironmentID'
          Value: !Select [ 0, !Split [ ".", !Select [ 1, !Split [ "https://", !Ref pDynatraceUrl ] ] ] ]

  DynatraceSettingsTokenSecretResourcePolicyOrgsAccess:
    Type: AWS::SecretsManager::ResourcePolicy
    Condition: cIsManagementRegion
    Properties:
      BlockPublicPolicy: false
      SecretId: !Ref DynatraceSettingsTokenSecret
      ResourcePolicy:
        Version: '2012-10-17'
        Statement:
          - Sid: AllowOrgAccountsAccessToDynatraceIntegrationSecretViaLambdaRole
            Effect: Allow
            Principal:
              AWS: '*'
            Action:
              - 'secretsmanager:GetSecretValue'
            Resource: '*'
            Condition:
              StringEquals:
                'aws:PrincipalOrgID': !Ref pAwsOrganizationId
              ArnLike:
                'aws:PrincipalArn': !Sub
                  - 'arn:aws:iam::*:role/DynatraceApiClientRole-${DynatraceEnvironmentId}-*'
                  - DynatraceEnvironmentId: !Select [ 0, !Split [ ".", !Select [ 1, !Split [ "https://", !Ref pDynatraceUrl ] ] ] ]

  DynatraceIngestTokenSecret:
    Type: AWS::SecretsManager::Secret
    Condition: cDynatraceIngestTokenIsSet
    Properties:
      Name: !Sub
        - '/dynatrace/${DynatraceEnvironmentId}/tokens/aws/${pAwsOrganizationId}/ingest/${pDeploymentInstanceIdentifier}'
        - DynatraceEnvironmentId: !Select [ 0, !Split [ ".", !Select [ 1, !Split [ "https://", !Ref pDynatraceUrl ] ] ] ]
      Description: 'Dynatrace Log and Event Ingest Platform token'
      SecretString: !Sub '{"api_key": "${pDtIngestToken}"}'
      KmsKeyId: !GetAtt DynatraceKMSKey.Arn
      Tags:
        - Key: 'dt:CreatedBy'
          Value: 'Dynatrace'
        - Key: 'dt:EnvironmentID'
          Value: !Select [ 0, !Split [ ".", !Select [ 1, !Split [ "https://", !Ref pDynatraceUrl ] ] ] ]

  DynatraceIngestTokenSecretResourcePolicyOrgsAccess:
    Type: AWS::SecretsManager::ResourcePolicy
    Condition: cDynatraceIngestTokenIsSet
    Properties:
      BlockPublicPolicy: false
      SecretId: !Ref DynatraceIngestTokenSecret
      ResourcePolicy:
        Version: '2012-10-17'
        Statement:
          - Sid: AllowOrgAccountsAccessToDynatraceIngestSecretViaStackSetRoles
            Effect: Allow
            Principal:
              AWS: '*'
            Action:
              - 'secretsmanager:GetSecretValue'
            Resource: '*'
            Condition:
              StringEquals:
                'aws:PrincipalOrgID': !Ref pAwsOrganizationId
              ArnLike:
                'aws:PrincipalArn':
                  - !Sub
                    - 'arn:aws:iam::*:role/DynatraceDeliveryStreamRole-${DynatraceEnvironmentId}-${AWS::Region}-*'
                    - DynatraceEnvironmentId: !Select [ 0, !Split [ ".", !Select [ 1, !Split [ "https://", !Ref pDynatraceUrl ] ] ] ]
          - Sid: AllowOrgAccountsAccessToDynatraceIngestSecretViaStackSetsExecutionRoles
            Effect: Allow
            Principal:
              AWS: '*'
            Action:
              - 'secretsmanager:GetSecretValue'
            Resource: '*'
            Condition:
              StringEquals:
                'aws:PrincipalOrgID': !Ref pAwsOrganizationId
              ArnLike:
                'aws:PrincipalArn': 'arn:aws:iam::*:role/stacksets-exec-*'

Outputs:
  DynatraceDeploymentInstanceIdentifier:
    Description: 'Deployment instance identifier'
    Value: !Ref pDeploymentInstanceIdentifier
  DynatraceSettingsTokenSecretArn:
    Description: 'ARN of the Dynatrace API Token Secret'
    Condition: cIsManagementRegion
    Value: !Ref DynatraceSettingsTokenSecret
  DynatraceIngestTokenSecretArn:
    Description: 'ARN of the Dynatrace Log and Event Ingest Secret'
    Value: !If
      - cDynatraceIngestTokenIsSet
      - !Ref DynatraceIngestTokenSecret
      - 'Ingest token not set'
  DynatraceKMSKeyArn:
    Description: 'ARN of the KMS Key used to encrypt Dynatrace tokens'
    Value: !GetAtt DynatraceKMSKey.Arn
