aws-cdk-lib#Token TypeScript Examples

The following examples show how to use aws-cdk-lib#Token. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: manifest.ts    From cloudstructs with Apache License 2.0 6 votes vote down vote up
function validateUrl(url?: string, https = true): void {
  if (url && !Token.isUnresolved(url)) {
    try {
      const parsed = new nodeUrl.URL(url);
      if (https && parsed.protocol !== 'https:') {
        throw new Error('Invalid protocol');
      }
    } catch (err) {
      throw new Error(`${url} is not a valid${https ? ' HTTPS' : ''} url`);
    }
  }
}
Example #2
Source File: index.ts    From cloudstructs with Apache License 2.0 6 votes vote down vote up
function shouldAddRedirect(props: StaticWebsiteProps): boolean {
  if (props.redirects && props.redirects.length === 0) {
    return false;
  }

  if (!props.redirects && !Token.isUnresolved(props.domainName)
      && !Token.isUnresolved(props.hostedZone.zoneName)
      && props.domainName === props.hostedZone.zoneName) {
    return false;
  }

  return true;
}
Example #3
Source File: aurora-serverless.ts    From bastion-host-forward with Apache License 2.0 6 votes vote down vote up
constructor(scope: Construct, id: string, props: BastionHostAuroraServerlessForwardProps) {
    super(scope, id, {
      vpc: props.vpc,
      name: props.name,
      securityGroup: props.securityGroup,
      address: props.serverlessCluster.clusterEndpoint.hostname,
      port: Token.asString(props.serverlessCluster.clusterEndpoint.port),
      clientTimeout: props.clientTimeout,
      serverTimeout: props.serverTimeout,
    });

    if (props.iamUser !== undefined && props.resourceIdentifier !== undefined) {
      this.bastionHost.instance.addToRolePolicy(
        new iam.PolicyStatement({
          effect: iam.Effect.ALLOW,
          actions: ['rds-db:connect', 'rds:*'],
          resources: [
            this.genDbUserArnFromRdsArn(props.resourceIdentifier, props.iamUser),
            props.serverlessCluster.clusterArn,
          ],
        }),
      );
    }
  }
Example #4
Source File: manifest.ts    From cloudstructs with Apache License 2.0 5 votes vote down vote up
function validateLength(description: string, max: number, xs?: string): void {
  if (xs && !Token.isUnresolved(xs) && xs.length > max) {
    throw new Error(`Maximum length for ${description} is ${max}, got ${xs.length}: ${xs}`);
  }
}
Example #5
Source File: manifest.ts    From cloudstructs with Apache License 2.0 5 votes vote down vote up
function validateItems<T>(description: string, max: number, xs?: T[]): void {
  if (xs && !Token.isUnresolved(xs) && xs.length > max) {
    throw new Error(`Maximum number of items for ${description} is ${max}, got ${xs.length}`);
  }
}
Example #6
Source File: manifest.ts    From cloudstructs with Apache License 2.0 5 votes vote down vote up
function validateColor(color?: string): void {
  if (color && !Token.isUnresolved(color) && !/^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(color)) {
    throw new Error(`Invalid hex color: ${color}`);
  }
}
Example #7
Source File: dns-validated-domain-identity.ts    From aws-cdk-ses-domain-identity with MIT License 5 votes vote down vote up
public constructor(scope: Construct, id: string, props: DnsValidatedDomainIdentityProps) {
    super(scope, id);

    const stack = Stack.of(this);

    const region = props.region ?? stack.region;
    const accountId = stack.account;

    this.domainName = props.domainName;
    this.dkim = props.dkim ?? false;
    this.identityArn = `arn:aws:ses:${region}:${accountId}:identity/${this.domainName}`;
    this.normalizedZoneName = props.hostedZone.zoneName;
    // Remove trailing `.` from zone name
    if (this.normalizedZoneName.endsWith(".")) {
      this.normalizedZoneName = this.normalizedZoneName.substring(0, this.normalizedZoneName.length - 1);
    }

    // Remove any `/hostedzone/` prefix from the Hosted Zone ID
    this.hostedZoneId = props.hostedZone.hostedZoneId.replace(/^\/hostedzone\//, "");

    const requestorFunction = new lambda.Function(this, "DomainIdentityRequestorFunction", {
      code: lambda.Code.fromAsset(path.resolve(__dirname, "..", "lambda-packages", "dns-validated-domain-identity-handler", "dist")),
      handler: "index.identityRequestHandler",
      runtime: lambda.Runtime.NODEJS_14_X,
      memorySize: 128,
      timeout: Duration.minutes(15),
      role: props.customResourceRole,
    });
    requestorFunction.addToRolePolicy(new iam.PolicyStatement({
      actions: [
        "ses:GetIdentityVerificationAttributes",
        "ses:GetIdentityDkimAttributes",
        "ses:SetIdentityDkimEnabled",
        "ses:VerifyDomainIdentity",
        "ses:VerifyDomainDkim",
        "ses:ListIdentities",
        "ses:DeleteIdentity",
      ],
      resources: ["*"],
    }));
    requestorFunction.addToRolePolicy(new iam.PolicyStatement({
      actions: ["route53:GetChange"],
      resources: ["*"],
    }));
    requestorFunction.addToRolePolicy(new iam.PolicyStatement({
      actions: [
          "route53:changeResourceRecordSets",
          "route53:ListResourceRecordSets",
      ],
      resources: [`arn:${Stack.of(requestorFunction).partition}:route53:::hostedzone/${this.hostedZoneId}`],
    }));

    const identity = new CustomResource(this, "IdentityRequestorResource", {
      serviceToken: requestorFunction.functionArn,
      properties: {
        DomainName: this.domainName,
        HostedZoneId: this.hostedZoneId,
        Region: region,
        DKIM: props.dkim,
      },
    });

    this.node.addValidation({
      validate: (): string[] => {
        const errors: string[] = [];
        // Ensure the zone name is a parent zone of the certificate domain name
        if (!Token.isUnresolved(this.normalizedZoneName) &&
          this.domainName !== this.normalizedZoneName &&
          !this.domainName.endsWith("." + this.normalizedZoneName)) {
          errors.push(`DNS zone ${this.normalizedZoneName} is not authoritative for SES identity domain name ${this.domainName}`);
        }

        return errors;
      },
    });
  }
Example #8
Source File: dns-validated-domain-identitiy.test.ts    From aws-cdk-ses-domain-identity with MIT License 4 votes vote down vote up
describe(DnsValidatedDomainIdentity.name, () => {
  it("creates CloudFormation Custom Resource", () => {
    const stack = new Stack();

    const exampleDotComZone = new PublicHostedZone(stack, "ExampleDotCom", {
      zoneName: "example.com",
    });

    // tslint:disable-next-line:no-unused-expression
    new DnsValidatedDomainIdentity(stack, "DomainIdentity", {
      domainName: "test.example.com",
      hostedZone: exampleDotComZone,
    });

    Template.fromStack(stack).hasResourceProperties("AWS::CloudFormation::CustomResource", {
      DomainName: "test.example.com",
      ServiceToken: {
        "Fn::GetAtt": [
          "DomainIdentityDomainIdentityRequestorFunction700A5CBC",
          "Arn",
        ],
      },
      HostedZoneId: {
        Ref: "ExampleDotCom4D1B83AA",
      },
    });

    Template.fromStack(stack).hasResourceProperties("AWS::Lambda::Function", {
      Handler: "index.identityRequestHandler",
      Runtime: "nodejs14.x",
      MemorySize: 128,
      Timeout: 900,
    });

    Template.fromStack(stack).hasResourceProperties("AWS::IAM::Policy", {
      PolicyName: "DomainIdentityDomainIdentityRequestorFunctionServiceRoleDefaultPolicy9D23D5BE",
      Roles: [
        {
          Ref: "DomainIdentityDomainIdentityRequestorFunctionServiceRoleD8F10EBD",
        },
      ],
      PolicyDocument: {
        Version: "2012-10-17",
        Statement: [
          {
            Action: [
              "ses:GetIdentityVerificationAttributes",
              "ses:GetIdentityDkimAttributes",
              "ses:SetIdentityDkimEnabled",
              "ses:VerifyDomainIdentity",
              "ses:VerifyDomainDkim",
              "ses:ListIdentities",
              "ses:DeleteIdentity",
            ],
            Effect: "Allow",
            Resource: "*",
          },
          {
            Action: "route53:GetChange",
            Effect: "Allow",
            Resource: "*",
          },
          {
            Action: [
              "route53:changeResourceRecordSets",
              "route53:ListResourceRecordSets",
            ],
            Effect: "Allow",
            Resource: {
              "Fn::Join": [
                "",
                [
                  "arn:",
                  { Ref: "AWS::Partition" },
                  ":route53:::hostedzone/",
                  { Ref: "ExampleDotCom4D1B83AA" },
                ],
              ],
            },
          },
        ],
      },
    });
  });

  it("adds validation error on domain mismatch", () => {
    const stack = new Stack();

    const helloDotComZone = new PublicHostedZone(stack, "HelloDotCom", {
      zoneName: "hello.com",
    });

    // tslint:disable-next-line:no-unused-expression
    new DnsValidatedDomainIdentity(stack, "DomainIdentity", {
      domainName: "example.com",
      hostedZone: helloDotComZone,
    });

    expect(() => Template.fromStack(stack))
      .toThrow(/DNS zone hello.com is not authoritative for SES identity domain name example.com/);
  });

  it("does not try to validate unresolved tokens", () => {
    const stack = new Stack();

    const helloDotComZone = new PublicHostedZone(stack, "HelloDotCom", {
      zoneName: Token.asString("hello.com"),
    });

    // tslint:disable-next-line:no-unused-expression
    new DnsValidatedDomainIdentity(stack, "DomainIdentity", {
      domainName: "hello.com",
      hostedZone: helloDotComZone,
    });

    expect(() => Template.fromStack(stack)).not.toThrow();
  });

  it("works with imported zone", () => {
    // GIVEN
    const app = new App();
    const stack = new Stack(app, "Stack", {
      env: { account: "12345678", region: "us-blue-5" },
    });
    const imported = HostedZone.fromLookup(stack, "ExampleDotCom", {
      domainName: "mydomain.com",
    });

    // WHEN
    // tslint:disable-next-line:no-unused-expression
    new DnsValidatedDomainIdentity(stack, "DomainIdentity", {
      domainName: "mydomain.com",
      hostedZone: imported,
    });

    // THEN
    Template.fromStack(stack).hasResourceProperties("AWS::CloudFormation::CustomResource", {
      ServiceToken: {
        "Fn::GetAtt": [
          "DomainIdentityDomainIdentityRequestorFunction700A5CBC",
          "Arn",
        ],
      },
      DomainName: "mydomain.com",
      HostedZoneId: "DUMMY",
    });
  });

  it("works with imported role", () => {
    // GIVEN
    const app = new App();
    const stack = new Stack(app, "Stack", {
      env: { account: "12345678", region: "us-blue-5" },
    });
    const helloDotComZone = new PublicHostedZone(stack, "HelloDotCom", {
      zoneName: "hello.com",
    });
    const role = iam.Role.fromRoleArn(stack, "Role", "arn:aws:iam::account-id:role/role-name");

    // WHEN
    // tslint:disable-next-line:no-unused-expression
    new DnsValidatedDomainIdentity(stack, "DomainIdentity", {
      domainName: "hello.com",
      hostedZone: helloDotComZone,
      customResourceRole: role,
    });

    // THEN
    Template.fromStack(stack).hasResourceProperties("AWS::Lambda::Function", {
      Role: "arn:aws:iam::account-id:role/role-name",
    });
  });

  it("exposes properties related to identity", () => {
    const app = new App();
    const stack = new Stack(app, "Stack", {
      env: { account: "12345678", region: "us-blue-5" },
    });

    const helloDotComZone = new PublicHostedZone(stack, "HelloDotCom", {
      zoneName: "example.com",
    });

    const identity = new DnsValidatedDomainIdentity(stack, "DomainIdentity", {
      domainName: "test.example.com",
      hostedZone: helloDotComZone,
    });

    expect(identity.identityArn).toEqual("arn:aws:ses:us-blue-5:12345678:identity/test.example.com");
  });
});
Example #9
Source File: gitlab-runner-instance.ts    From cdk-gitlab-runner with Apache License 2.0 4 votes vote down vote up
constructor(scope: Construct, id: string, props: GitlabContainerRunnerProps) {
    super(scope, id);
    const spotFleetId = id;

    const defaultProps = {
      gitlabRunnerImage: 'public.ecr.aws/gitlab/gitlab-runner:alpine',
      gitlaburl: 'https://gitlab.com/',
      ec2type: 't3.micro',
      tags: ['gitlab', 'awscdk', 'runner'],
    };
    const runnerProps = { ...defaultProps, ...props };

    const runnerBucket = new Bucket(this, 'runnerBucket', {
      removalPolicy: RemovalPolicy.DESTROY,
      autoDeleteObjects: true,
    });
    const shell = UserData.forLinux();
    shell.addCommands(...this.createUserData(runnerProps, runnerBucket.bucketName));

    this.runnerRole =
      runnerProps.ec2iamrole ??
      new Role(this, 'runner-role', {
        assumedBy: new ServicePrincipal('ec2.amazonaws.com'),
        description: 'For Gitlab EC2 Runner Role',
      });
    this.validUntil = runnerProps.validUntil;
    const instanceProfile = new CfnInstanceProfile(this, 'InstanceProfile', {
      roles: [this.runnerRole.roleName],
    });
    runnerBucket.grantWrite(this.runnerRole);
    this.vpc =
      runnerProps.selfvpc ??
      new Vpc(this, 'VPC', {
        cidr: '10.0.0.0/16',
        maxAzs: 2,
        subnetConfiguration: [
          {
            cidrMask: 26,
            name: 'RunnerVPC',
            subnetType: SubnetType.PUBLIC,
          },
        ],
        natGateways: 0,
      });
    this.defaultRunnerSG = new SecurityGroup(this, 'SpotFleetSg', {
      vpc: this.vpc,
    });
    this.defaultRunnerSG.connections.allowFromAnyIpv4(Port.tcp(22));
    const spotOrOnDemand = runnerProps.spotFleet ?? false;
    if (spotOrOnDemand) {
      //throw new Error('yes new spotfleet');

      const imageId = MachineImage.latestAmazonLinux({
        generation: AmazonLinuxGeneration.AMAZON_LINUX_2,
      }).getImage(this).imageId;
      const lt = new CfnLaunchTemplate(this, 'LaunchTemplate', {
        launchTemplateData: {
          imageId,
          instanceType: runnerProps.ec2type,
          blockDeviceMappings: [
            {
              deviceName: '/dev/xvda',
              ebs: {
                volumeSize: runnerProps.ebsSize ?? 60,
              },
            },
          ],
          userData: Fn.base64(shell.render()),
          keyName: runnerProps.keyName,
          tagSpecifications: [
            {
              resourceType: 'instance',
              tags: [
                {
                  key: 'Name',
                  value: `${Stack.of(this).stackName
                  }/spotFleetGitlabRunner/${spotFleetId}`,
                },
              ],
            },
          ],
          instanceMarketOptions: {
            marketType: 'spot',
            spotOptions: {
              blockDurationMinutes:
                runnerProps.blockDuration ?? BlockDuration.ONE_HOUR,
              instanceInterruptionBehavior:
                runnerProps.instanceInterruptionBehavior ??
                InstanceInterruptionBehavior.TERMINATE,
            },
          },
          securityGroupIds: this.defaultRunnerSG.connections.securityGroups.map(
            (m) => m.securityGroupId,
          ),
          iamInstanceProfile: {
            arn: instanceProfile.attrArn,
          },
        },
      });

      const spotFleetRole = new Role(this, 'FleetRole', {
        assumedBy: new ServicePrincipal('spotfleet.amazonaws.com'),
        managedPolicies: [
          ManagedPolicy.fromAwsManagedPolicyName(
            'service-role/AmazonEC2SpotFleetTaggingRole',
          ),
        ],
      });

      const vpcSubnetSelection = runnerProps.vpcSubnet ?? {
        subnetType: SubnetType.PUBLIC,
      };
      const subnetConfig = this.vpc
        .selectSubnets(vpcSubnetSelection)
        .subnets.map((s) => ({
          subnetId: s.subnetId,
        }));

      const cfnSpotFleet = new CfnSpotFleet(this, id, {
        spotFleetRequestConfigData: {
          launchTemplateConfigs: [
            {
              launchTemplateSpecification: {
                launchTemplateId: lt.ref,
                version: lt.attrLatestVersionNumber,
              },
              overrides: subnetConfig,
            },
          ],
          iamFleetRole: spotFleetRole.roleArn,
          targetCapacity: 1,
          validUntil: Lazy.string({ produce: () => this.validUntil }),
          terminateInstancesWithExpiration: true,
        },
      });
      const onEvent = new lambda.Function(this, 'OnEvent', {
        code: lambda.Code.fromAsset(path.join(__dirname, '../assets/functions')),
        handler: 'index.on_event',
        runtime: lambda.Runtime.PYTHON_3_8,
        timeout: Duration.seconds(60),
      });

      const isComplete = new lambda.Function(this, 'IsComplete', {
        code: lambda.Code.fromAsset(path.join(__dirname, '../assets/functions')),
        handler: 'index.is_complete',
        runtime: lambda.Runtime.PYTHON_3_8,
        timeout: Duration.seconds(60),
        role: onEvent.role,
      });

      const myProvider = new cr.Provider(this, 'MyProvider', {
        onEventHandler: onEvent,
        isCompleteHandler: isComplete,
        logRetention: logs.RetentionDays.ONE_DAY,
      });

      onEvent.addToRolePolicy(
        new PolicyStatement({
          actions: ['ec2:DescribeSpotFleetInstances'],
          resources: ['*'],
        }),
      );

      const fleetInstances = new CustomResource(this, 'GetInstanceId', {
        serviceToken: myProvider.serviceToken,
        properties: {
          SpotFleetRequestId: cfnSpotFleet.ref,
        },
      });

      fleetInstances.node.addDependency(cfnSpotFleet);
      this.spotFleetInstanceId = Token.asString(
        fleetInstances.getAtt('InstanceId'),
      );
      this.spotFleetRequestId = Token.asString(
        fleetInstances.getAtt('SpotInstanceRequestId'),
      );
      new CfnOutput(this, 'InstanceId', { value: this.spotFleetInstanceId });
      new CfnOutput(this, 'SpotFleetId', { value: cfnSpotFleet.ref });
    } else {
      this.runnerEc2 = new Instance(this, 'GitlabRunner', {
        instanceType: new InstanceType(runnerProps.ec2type),
        instanceName: 'Gitlab-Runner',
        vpc: this.vpc,
        vpcSubnets: runnerProps.vpcSubnet ?? {
          subnetType: SubnetType.PUBLIC,
        },
        machineImage: MachineImage.latestAmazonLinux({
          generation: AmazonLinuxGeneration.AMAZON_LINUX_2,
        }),
        role: this.runnerRole,
        userData: shell,
        securityGroup: this.defaultRunnerSG,
        blockDevices: [
          {
            deviceName: '/dev/xvda',
            volume: BlockDeviceVolume.ebs(runnerProps.ebsSize ?? 60),
          },
        ],
      });
      new CfnOutput(this, 'Runner-Instance-ID', {
        value: this.runnerEc2.instanceId,
      });
    }

    const unregisterRunnerOnEvent = new lambda.Function(this, 'unregisterRunnerOnEvent', {
      code: lambda.Code.fromAsset(path.join(__dirname, '../assets/functions')),
      handler: 'unregister_runner.on_event',
      runtime: lambda.Runtime.PYTHON_3_8,
      timeout: Duration.seconds(60),
    });

    const unregisterRunnerProvider = new cr.Provider(this, 'unregisterRunnerProvider', {
      onEventHandler: unregisterRunnerOnEvent,
      logRetention: logs.RetentionDays.ONE_DAY,
    });

    const unregisterRunnerCR = new CustomResource(this, 'unregisterRunnerCR', {
      resourceType: 'Custom::unregisterRunnerProvider',
      serviceToken: unregisterRunnerProvider.serviceToken,
      properties: {
        BucketName: runnerBucket.bucketName,
        GitlabUrl: runnerProps.gitlaburl,
      },
    });

    runnerBucket.grantReadWrite(unregisterRunnerOnEvent);
    unregisterRunnerCR.node.addDependency(runnerBucket);
    this.runnerRole.addManagedPolicy(
      ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore'),
    );

    new CfnOutput(this, 'Runner-Role-Arn', {
      value: this.runnerRole.roleArn,
    });
  }