Code build で kubectl を実行できるようにした話

# はじめに

[Releaseタグ作成からEKSへのデプロイを自動化した話](https://qiita.com/ijufumi/items/c8c54c2295baf04113b2) でやった内容のうち、 `Code build` に焦点を当てた内容です。

載せているコードは一部だけなので、全体を見たい方は上記の記事から辿ってください。

# 環境

* `Kubernetes`: `1.24`
* `AWS CDK for Golang`: `v2.56.1`

# やったこと

## `MasterRole` を作成

`AWS CDK` で `Cluster` を作成した後に、 `MasterRole` を参照することができなかったので、 `Cluster` を作成する時に明示的に `MasterRole` を設定しました。

```golang
eksMasterRole := awsiam.NewRole(scope, jsii.String("id-eks-master-role"), &awsiam.RoleProps{
    AssumedBy: awsiam.NewAccountRootPrincipal(),
})

subnets := []*awsec2.SubnetSelection{
    {
        SubnetType: awsec2.SubnetType_PRIVATE_WITH_EGRESS,
    },
}
props := awseks.FargateClusterProps{
    Version:      awseks.KubernetesVersion_Of(jsii.String(config.Cluster.K8SVersion)),
    KubectlLayer: kubectl.NewKubectlLayer(scope, jsii.String("id-kubectl-layer")),
    ClusterName:  jsii.String(config.Cluster.Name),
    MastersRole:  eksMasterRole,
    Vpc:          vpc,
    VpcSubnets:   &subnets,
    AlbController: &awseks.AlbControllerOptions{
        Version: awseks.AlbControllerVersion_V2_4_1(),
    },
}

cluster := awseks.NewFargateCluster(scope, jsii.String("eks-cluster-id"), &props)
```

## `Code build` の環境変数に `Role` の `ARN` を設定

`Code build` の中で `kubectl` を実行する時に `--role-arn` を指定する必要があるので、それで使うために環境変数に設定しました。

```golang
buildAction := actions.NewCodeBuildAction(
    &actions.CodeBuildActionProps{
        ActionName: jsii.String("build"),
        Input:      sourceOutput,
        Project:    buildProject,
        EnvironmentVariables: &map[string]*build.BuildEnvironmentVariable{
            "IMAGE_REPO_NAME": {
                Value: jsii.String(config.Repository.Name),
                Type:  build.BuildEnvironmentVariableType_PLAINTEXT,
            },
            "WEB_HOOK_URL": {
                Value: jsii.String(config.Slack.WebHookURL),
                Type:  build.BuildEnvironmentVariableType_PLAINTEXT,
            },
            "AWS_ACCOUNT_ID": {
                Value: config.GetAwsAccountID(),
                Type:  build.BuildEnvironmentVariableType_PLAINTEXT,
            },
            "EKS_CLUSTER_NAME": {
                Value: jsii.String(config.Cluster.Name),
                Type:  build.BuildEnvironmentVariableType_PLAINTEXT,
            },
            "EKS_CLUSTER_ROLE": {
                Value: eksMasterRole.RoleArn(),
                Type:  build.BuildEnvironmentVariableType_PLAINTEXT,
            },
            "DOCKER_USER": {
                Value: dockerUser.ParameterName(),
                Type:  build.BuildEnvironmentVariableType_PARAMETER_STORE,
            },
            "DOCKER_TOKEN": {
                Value: dockerToken.ParameterName(),
                Type:  build.BuildEnvironmentVariableType_PARAMETER_STORE,
            },
        },
    },
)
```

## `Code build` の `Role` に必要な権限を追加

`kubectl` コマンドを実行するために、 `eks:DescribeCluster` と `sts:AssumeRole` がそれぞれ必要だったので追加しました。

```golang
buildRole.AddToPolicy(awsiam.NewPolicyStatement(&awsiam.PolicyStatementProps{
    Actions:   jsii.Strings("eks:DescribeCluster"),
    Effect:    awsiam.Effect_ALLOW,
    Resources: jsii.Strings(*cluster.ClusterArn()),
}))
buildRole.AddToPolicy(awsiam.NewPolicyStatement(&awsiam.PolicyStatementProps{
    Actions:   jsii.Strings("sts:AssumeRole"),
    Effect:    awsiam.Effect_ALLOW,
    Resources: jsii.Strings(*eksMasterRole.RoleArn()),
}))
```

## `buildspec.yml` に `aws eks update-kubeconfig` を追加

ローカルで実行するときと同様に `kubectl` でアクセスするために `aws eks update-kubeconfig` を実行する必要があるので、このコマンドを追加しました。

また、ロールを指定する必要があるので　`--role-arn` オプションを追加しています。

```yaml
- aws eks update-kubeconfig --name ${EKS_CLUSTER_NAME} --region ${AWS_DEFAULT_REGION}  --role-arn ${EKS_CLUSTER_ROLE}
```

# 最後に

今回色々試してみて最終的に上記の通りやることで、動くようになりました。
もし「この方法がより良いやり方だよ」ってのがありましたらコメント頂けると幸いです。