constructor()

in eks-fargate/lib/infra-stack.ts [13:587]


  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const repository = codecommit.Repository.fromRepositoryName(
      this,
      `${ProjectName}-repo`,
      ProjectName
    );

    const ecrRepo = new ecr.Repository(this, `${ProjectName}`, {
      repositoryName: `${ProjectName}`,
    });

    const baseVpc = new ec2.Vpc(this, `${ProjectName}-vpc`, {
      maxAzs: 3,
    });

    const clusterAdmin = new iam.Role(this, "AdminRole", {
      assumedBy: new iam.AccountRootPrincipal(),
    });

    const eksCluster = new eks.FargateCluster(this, `${ProjectName}-eks`, {
      vpc: baseVpc,
      version: eks.KubernetesVersion.V1_19,
      mastersRole: clusterAdmin,
    });

    const ns = eksCluster.addManifest(`${ProjectName}-ns`, {
      apiVersion: "v1",
      kind: "Namespace",
      metadata: {
        name: ProjectName,
      },
    });

    const podRole = new iam.Role(this, `${ProjectName}-pod-role`, {
      assumedBy: new iam.ServicePrincipal("eks-fargate-pods.amazonaws.com"),
      managedPolicies: [
        iam.ManagedPolicy.fromAwsManagedPolicyName(
          "AmazonEKSFargatePodExecutionRolePolicy"
        ),
        iam.ManagedPolicy.fromAwsManagedPolicyName(
          "CloudWatchAgentServerPolicy"
        ),
      ],
    });

    podRole.addToPolicy(
      new iam.PolicyStatement({
        actions: ["sdkmetrics:*"],
        effect: iam.Effect.ALLOW,
        resources: ["*"],
      })
    );

    podRole.addToPolicy(
      new iam.PolicyStatement({
        actions: [
          "logs:CreateLogGroup",
          "logs:CreateLogStream",
          "logs:PutLogEvents",
          "logs:DescribeLogStreams",
        ],
        effect: iam.Effect.ALLOW,
        resources: ["*"],
      })
    );

    eksCluster.addFargateProfile(`${ProjectName}-profile`, {
      selectors: [{ namespace: ProjectName }],
      podExecutionRole: podRole,
    });

    const serviceAccount = eksCluster.addServiceAccount("ServiceAccount", {
      name: "alb-ingress-controller",
      namespace: "kube-system",
    });

    serviceAccount.addToPolicy(
      new iam.PolicyStatement({
        actions: [
          "acm:DescribeCertificate",
          "acm:ListCertificates",
          "acm:GetCertificate",
        ],
        effect: iam.Effect.ALLOW,
        resources: ["*"],
      })
    );

    serviceAccount.addToPolicy(
      new iam.PolicyStatement({
        actions: [
          "ec2:AuthorizeSecurityGroupIngress",
          "ec2:CreateSecurityGroup",
          "ec2:CreateTags",
          "ec2:DeleteTags",
          "ec2:DeleteSecurityGroup",
          "ec2:DescribeAccountAttributes",
          "ec2:DescribeAddresses",
          "ec2:DescribeInstances",
          "ec2:DescribeInstanceStatus",
          "ec2:DescribeInternetGateways",
          "ec2:DescribeNetworkInterfaces",
          "ec2:DescribeSecurityGroups",
          "ec2:DescribeSubnets",
          "ec2:DescribeTags",
          "ec2:DescribeVpcs",
          "ec2:ModifyInstanceAttribute",
          "ec2:ModifyNetworkInterfaceAttribute",
          "ec2:RevokeSecurityGroupIngress",
        ],
        effect: iam.Effect.ALLOW,
        resources: ["*"],
      })
    );

    serviceAccount.addToPolicy(
      new iam.PolicyStatement({
        actions: [
          "elasticloadbalancing:AddListenerCertificates",
          "elasticloadbalancing:AddTags",
          "elasticloadbalancing:CreateListener",
          "elasticloadbalancing:CreateLoadBalancer",
          "elasticloadbalancing:CreateRule",
          "elasticloadbalancing:CreateTargetGroup",
          "elasticloadbalancing:DeleteListener",
          "elasticloadbalancing:DeleteLoadBalancer",
          "elasticloadbalancing:DeleteRule",
          "elasticloadbalancing:DeleteTargetGroup",
          "elasticloadbalancing:DeregisterTargets",
          "elasticloadbalancing:DescribeListenerCertificates",
          "elasticloadbalancing:DescribeListeners",
          "elasticloadbalancing:DescribeLoadBalancers",
          "elasticloadbalancing:DescribeLoadBalancerAttributes",
          "elasticloadbalancing:DescribeRules",
          "elasticloadbalancing:DescribeSSLPolicies",
          "elasticloadbalancing:DescribeTags",
          "elasticloadbalancing:DescribeTargetGroups",
          "elasticloadbalancing:DescribeTargetGroupAttributes",
          "elasticloadbalancing:DescribeTargetHealth",
          "elasticloadbalancing:ModifyListener",
          "elasticloadbalancing:ModifyLoadBalancerAttributes",
          "elasticloadbalancing:ModifyRule",
          "elasticloadbalancing:ModifyTargetGroup",
          "elasticloadbalancing:ModifyTargetGroupAttributes",
          "elasticloadbalancing:RegisterTargets",
          "elasticloadbalancing:RemoveListenerCertificates",
          "elasticloadbalancing:RemoveTags",
          "elasticloadbalancing:SetIpAddressType",
          "elasticloadbalancing:SetSecurityGroups",
          "elasticloadbalancing:SetSubnets",
          "elasticloadbalancing:SetWebAcl",
        ],
        effect: iam.Effect.ALLOW,
        resources: ["*"],
      })
    );

    serviceAccount.addToPolicy(
      new iam.PolicyStatement({
        actions: [
          "iam:CreateServiceLinkedRole",
          "iam:GetServerCertificate",
          "iam:ListServerCertificates",
        ],
        effect: iam.Effect.ALLOW,
        resources: ["*"],
      })
    );

    serviceAccount.addToPolicy(
      new iam.PolicyStatement({
        actions: ["cognito-idp:DescribeUserPoolClient"],
        effect: iam.Effect.ALLOW,
        resources: ["*"],
      })
    );

    serviceAccount.addToPolicy(
      new iam.PolicyStatement({
        actions: [
          "waf-regional:GetWebACLForResource",
          "waf-regional:GetWebACL",
          "waf-regional:AssociateWebACL",
          "waf-regional:DisassociateWebACL",
        ],
        effect: iam.Effect.ALLOW,
        resources: ["*"],
      })
    );

    serviceAccount.addToPolicy(
      new iam.PolicyStatement({
        actions: ["tag:GetResources", "tag:TagResources"],
        effect: iam.Effect.ALLOW,
        resources: ["*"],
      })
    );

    serviceAccount.addToPolicy(
      new iam.PolicyStatement({
        actions: ["waf:GetWebACL"],
        effect: iam.Effect.ALLOW,
        resources: ["*"],
      })
    );

    serviceAccount.addToPolicy(
      new iam.PolicyStatement({
        actions: [
          "wafv2:GetWebACL",
          "wafv2:GetWebACLForResource",
          "wafv2:AssociateWebACL",
          "wafv2:DisassociateWebACL",
        ],
        effect: iam.Effect.ALLOW,
        resources: ["*"],
      })
    );

    serviceAccount.addToPolicy(
      new iam.PolicyStatement({
        actions: [
          "shield:DescribeProtection",
          "shield:GetSubscriptionState",
          "shield:DeleteProtection",
          "shield:CreateProtection",
          "shield:DescribeSubscription",
          "shield:ListProtections",
        ],
        effect: iam.Effect.ALLOW,
        resources: ["*"],
      })
    );

    eksCluster
      .addManifest(`${ProjectName}-cluster-role`, {
        apiVersion: "rbac.authorization.k8s.io/v1",
        kind: "ClusterRole",
        metadata: {
          labels: {
            "app.kubernetes.io/name": "alb-ingress-controller",
          },
          name: "alb-ingress-controller",
        },
        rules: [
          {
            apiGroups: ["", "extensions"],
            resources: [
              "configmaps",
              "endpoints",
              "events",
              "ingresses",
              "ingresses/status",
              "services",
            ],
            verbs: ["create", "get", "list", "update", "watch", "patch"],
          },
          {
            apiGroups: ["", "extensions"],
            resources: ["nodes", "pods", "secrets", "services", "namespaces"],
            verbs: ["get", "list", "watch"],
          },
        ],
      })
      .node.addDependency(serviceAccount);

    eksCluster
      .addManifest(`${ProjectName}-cluster-binding`, {
        apiVersion: "rbac.authorization.k8s.io/v1",
        kind: "ClusterRoleBinding",
        metadata: {
          labels: {
            "app.kubernetes.io/name": "alb-ingress-controller",
          },
          name: "alb-ingress-controller",
        },
        roleRef: {
          apiGroup: "rbac.authorization.k8s.io",
          kind: "ClusterRole",
          name: "alb-ingress-controller",
        },
        subjects: [
          {
            kind: "ServiceAccount",
            name: "alb-ingress-controller",
            namespace: "kube-system",
          },
        ],
      })
      .node.addDependency(serviceAccount);

    const albIngress = eksCluster.addManifest(`${ProjectName}-alb-ingress`, {
      apiVersion: "apps/v1",
      kind: "Deployment",
      metadata: {
        labels: {
          "app.kubernetes.io/name": "alb-ingress-controller",
        },
        name: "alb-ingress-controller",
        namespace: "kube-system",
      },
      spec: {
        selector: {
          matchLabels: {
            "app.kubernetes.io/name": "alb-ingress-controller",
          },
        },
        template: {
          metadata: {
            labels: {
              "app.kubernetes.io/name": "alb-ingress-controller",
            },
          },
          spec: {
            containers: [
              {
                name: "alb-ingress-controller",
                args: [
                  "--ingress-class=alb",
                  `--cluster-name=${eksCluster.clusterName}`,
                  `--aws-vpc-id=${baseVpc.vpcId}`,
                  `--aws-region=${this.region}`,
                ],
                image: "docker.io/amazon/aws-alb-ingress-controller:v1.1.8",
              },
            ],
            serviceAccountName: "alb-ingress-controller",
          },
        },
      },
    });

    albIngress.node.addDependency(serviceAccount);

    const cloudWatchAgentConfig = eksCluster.addManifest(
      "cwagentconfig-sidecar",
      {
        apiVersion: "v1",
        kind: "ConfigMap",
        metadata: {
          name: "cwagentconfig-sidecar",
          namespace: ProjectName,
        },
        data: {
          "cwagentconfig.json":
            '{\n  "agent": {\n    "omit_hostname": true, "region": "us-east-1"\n  },\n  "metrics": {\n    "metrics_collected": {\n      "statsd": {\n        "service_address":":8125"\n      }\n    }\n  },\n  "logs": {\n    "metrics_collected": {\n      "emf": {}\n    }\n  },\n  "csm": {\n    "service_addresses": ["udp4://127.0.0.1:31000", "udp6://[::1]:31000"],\n    "memory_limit_in_mb": 20\n  }\n}\n',
        },
      }
    );

    cloudWatchAgentConfig.node.addDependency(ns);

    eksCluster
      .addManifest(`${ProjectName}-deployment`, {
        apiVersion: "apps/v1",
        kind: "Deployment",
        metadata: {
          name: ProjectName,
          namespace: ProjectName,
        },
        spec: {
          selector: {
            matchLabels: {
              app: ProjectName,
            },
          },
          replicas: 3,
          template: {
            metadata: {
              labels: {
                app: ProjectName,
              },
            },
            spec: {
              containers: [
                {
                  image: `${ecrRepo.repositoryUri}:latest`,
                  imagePullPolicy: "Always",
                  name: ProjectName,
                  ports: [
                    {
                      containerPort: 8080,
                    },
                  ],
                  env: [
                    { name: "AWS_CSM_ENABLED", value: "true" },
                    { name: "AWS_CSM_PORT", value: "31000" },
                    { name: "AWS_CSM_HOST", value: "127.0.0.1" },
                  ],
                },
                {
                  name: "cloudwatch-agent",
                  image: "amazon/cloudwatch-agent:latest",
                  imagePullPolicy: "Always",
                  env: [
                    {
                      name: "POD_NAME",
                      valueFrom: {
                        fieldRef: {
                          fieldPath: "metadata.name",
                        },
                      },
                    },
                  ],
                  resources: {
                    limits: {
                      cpu: "100m",
                      memory: "100Mi",
                    },
                    requests: {
                      cpu: "32m",
                      memory: "24Mi",
                    },
                  },
                  volumeMounts: [
                    {
                      name: "cwagentconfig",
                      mountPath: "/etc/cwagentconfig",
                    },
                  ],
                },
              ],
              volumes: [
                {
                  name: "cwagentconfig",
                  configMap: {
                    name: "cwagentconfig-sidecar",
                  },
                },
              ],
            },
          },
        },
      })
      .node.addDependency(cloudWatchAgentConfig);

    const service = eksCluster.addManifest(`${ProjectName}-service`, {
      apiVersion: "v1",
      kind: "Service",
      metadata: {
        name: `${ProjectName}-service`,
        namespace: ProjectName,
      },
      spec: {
        ports: [
          {
            port: 80,
            targetPort: 8080,
            protocol: "TCP",
          },
        ],
        type: "NodePort",
        selector: {
          app: ProjectName,
        },
      },
    });

    service.node.addDependency(albIngress);

    eksCluster
      .addManifest(`${ProjectName}-ingress`, {
        apiVersion: "extensions/v1beta1",
        kind: "Ingress",
        metadata: {
          name: `${ProjectName}-ingress`,
          namespace: `${ProjectName}`,
          annotations: {
            "kubernetes.io/ingress.class": "alb",
            "alb.ingress.kubernetes.io/scheme": "internet-facing",
            "alb.ingress.kubernetes.io/target-type": "ip",
            "alb.ingress.kubernetes.io/healthcheck-path": "/actuator/health",
          },
          labels: {
            app: `${ProjectName}-ingress`,
          },
        },
        spec: {
          rules: [
            {
              http: {
                paths: [
                  {
                    path: "/*",
                    backend: {
                      serviceName: `${ProjectName}-service`,
                      servicePort: 80,
                    },
                  },
                ],
              },
            },
          ],
        },
      })
      .node.addDependency(service);

    const project = new codebuild.Project(this, `${ProjectName}-build`, {
      source: codebuild.Source.codeCommit({ repository }),
      environment: {
        buildImage: codebuild.LinuxBuildImage.fromAsset(
          this,
          `${ProjectName}-build-image`,
          {
            directory: "EKSBuild",
          }
        ),
        privileged: true,
      },
      environmentVariables: {
        CLUSTER_NAME: {
          value: `${eksCluster.clusterName}`,
        },
        ECR_REPO_URI: {
          value: `${ecrRepo.repositoryUri}`,
        },
      },
      buildSpec: codebuild.BuildSpec.fromObject({
        version: "0.2",
        phases: {
          pre_build: {
            commands: [
              "env",
              "export TAG=${CODEBUILD_RESOLVED_SOURCE_VERSION}",
              "/usr/local/bin/entrypoint.sh",
            ],
          },
          build: {
            commands: [
              `docker build -t $ECR_REPO_URI:$TAG .`,
              "$(aws ecr get-login --no-include-email)",
              "docker push $ECR_REPO_URI:$TAG",
            ],
          },
          post_build: {
            commands: [
              `kubectl set image deployment ${ProjectName} ${ProjectName}=$ECR_REPO_URI:$TAG -n ${ProjectName}`,
              `kubectl get svc -n ${ProjectName}`,
            ],
          },
        },
      }),
    });

    repository.onCommit("OnCommit", {
      target: new targets.CodeBuildProject(
        codebuild.Project.fromProjectArn(
          this,
          "OnCommitEvent",
          project.projectArn
        )
      ),
    });

    ecrRepo.grantPullPush(project.role!);
    eksCluster.awsAuth.addMastersRole(project.role!);
    project.addToRolePolicy(
      new iam.PolicyStatement({
        actions: ["eks:DescribeCluster"],
        resources: [`${eksCluster.clusterArn}`],
      })
    );

    new cdk.CfnOutput(this, "CodeCommitRepoName", {
      value: `${repository.repositoryName}`,
    });
    new cdk.CfnOutput(this, "EcrRepoArn", {
      value: `${ecrRepo.repositoryArn}`,
    });
    new cdk.CfnOutput(this, "CodeBuildProjectArn", {
      value: `${project.projectArn}`,
    });
  }