CodeCommitをTerraformでデプロイ

★ この記事は3年前に執筆し、投稿し忘れていたものを投稿したものです

## はじめに

AWSでのCICDを行う際、リポジトリにCodeCommitを使うことになりました。
存在は知っていましたが使ったことはありません。
非常にgitと親和性が高いという事は知っていましたので非常に興味があります。

## 参考

[Resource: aws_codecommit_repository](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/codecommit_repository)
[LambdaのCDをCodePipelineとCloudFormationで構築してみる](https://dev.classmethod.jp/articles/lambda-cd-cfn-codepipeline/)
[CloudFormationでLambdaの自動デプロイ環境を構築する](https://qiita.com/ytaka95/items/5899c44c85e71fdc5273#template_deployyml)

## 目的

CodeCommitにリポジトリを作成
作成したリポジトリに資材をアップロード(プッシュ)する

## 手順

### Dockerfileの修正

準備作業として、AWS CLIやTerraformが使えるコンテナを使っていますので、そちらでCodeCommitにアクセスできる環境も追加してみようと思います。

CodeCommitへアクセスするために必要な「git-remote-codecommit」をインストールする記述をDockerfileに追記しコンテナを起動しておきます。

```
# install git-remote-codecommit
RUN pip install git-remote-codecommit
```

### 事前準備

まず最初にお約束のaws configureを行います。

```
# aws configure
AWS Access Key ID [None]: xxxxx
AWS Secret Access Key [None]: xxxxx
Default region name [None]: us-west-2
Default output format [None]: json

# aws sts get-caller-identity
{
    "UserId": "xxxxx",
    "Account": "xxxxx",
    "Arn": "arn:aws:iam::xxxxx:user/xxxxx"
}
```

続いて、作業フォルダでterraformの初期化を行います。

```
# terraform init

Initializing the backend...

Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v3.63.0...
- Installed hashicorp/aws v3.63.0 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
```

### CodeCommitにリポジトリを作成

CodeCommitにリポジトリを登録するためのテンプレートファイルを準備しました。

codecommit.tf

```
resource "aws_codecommit_repository" "xxxxx_test" {
  repository_name = "xxxxx_test"
  description     = "This is the Sample App Repository"
}
```

テンプレートファイルの検証を行います。

```
# terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
following symbols:
  + create

Terraform will perform the following actions:

  # aws_codecommit_repository.xxxxx_test will be created
  + resource "aws_codecommit_repository" "xxxxx_test" {
      + arn             = (known after apply)
      + clone_url_http  = (known after apply)
      + clone_url_ssh   = (known after apply)
      + description     = "This is the Sample App Repository"
      + id              = (known after apply)
      + repository_id   = (known after apply)
      + repository_name = "xxxxx_test"
      + tags_all        = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if
you run "terraform apply" now.
```

問題がないという結果なので実際にデプロイします。
今回も「-auto-approve」オプションを使用して自動応答でデプロします。

```
# terraform apply -auto-approve

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
following symbols:
  + create

Terraform will perform the following actions:

  # aws_codecommit_repository.xxxxx_test will be created
  + resource "aws_codecommit_repository" "xxxxx_test" {
      + arn             = (known after apply)
      + clone_url_http  = (known after apply)
      + clone_url_ssh   = (known after apply)
      + description     = "This is the Sample App Repository"
      + id              = (known after apply)
      + repository_id   = (known after apply)
      + repository_name = "xxxxx_test"
      + tags_all        = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.
aws_codecommit_repository.xxxxx_test: Creating...
aws_codecommit_repository.xxxxx_test: Creation complete after 2s [id=xxxxx_test]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
```

正常にデプロイで来たようですが、実行結果を改めて確認しておきます。

```
# terraform show
# aws_codecommit_repository.xxxxx_test:
resource "aws_codecommit_repository" "xxxxx_test" {
    arn             = "arn:aws:codecommit:us-west-2:xxxxx:xxxxx_test"
    clone_url_http  = "https://git-codecommit.us-west-2.amazonaws.com/v1/repos/xxxxx_test"
    clone_url_ssh   = "ssh://git-codecommit.us-west-2.amazonaws.com/v1/repos/xxxxx_test"
    description     = "This is the Sample App Repository"
    id              = "xxxxx_test"
    repository_id   = "xxxxx"
    repository_name = "xxxxx_test"
    tags_all        = {}
}
```

続いて、aws cliのコマンドを使用してcodecommitからリポジトリ一覧を取得し、正しく登録されているのかを確認します。

が、ここで問題発生です。
aws cli コマンドのhelpでエラーが発生してしまいました。
エラーメッセージから調査を行うと、どうやら「groff」が必要のようです。
今回のコンテナはDebian系なので、「groff-base」をインストールすれば良いようです。

```
# aws codecommit help

Could not find executable named "groff"

# apt install -y groff-base
```

groffのインストールを終えましたので、codecommitの一覧を取得するために「list」と指定してみましたが、どうやらその様なコマンドは存在しないようです。
(事前調査せず実行したのでエラーになるだろうとは推測していました．．．)
実行した結果、利用可能なcodecommitのコマンド一覧が表示されました。

```
# aws codecommit list

usage: aws [options] <command> <subcommand> [<subcommand> ...] [parameters]
To see help text, you can run:

  aws help
  aws <command> help
  aws <command> <subcommand> help

aws: error: argument operation: Invalid choice, valid choices are:

associate-approval-rule-template-with-repository | batch-associate-approval-rule-template-with-repositories
batch-describe-merge-conflicts           | batch-disassociate-approval-rule-template-from-repositories
batch-get-commits                        | batch-get-repositories
create-approval-rule-template            | create-branch
create-commit                            | create-pull-request
create-pull-request-approval-rule        | create-repository
create-unreferenced-merge-commit         | delete-approval-rule-template
delete-branch                            | delete-comment-content
delete-file                              | delete-pull-request-approval-rule
delete-repository                        | describe-merge-conflicts
describe-pull-request-events             | disassociate-approval-rule-template-from-repository
evaluate-pull-request-approval-rules     | get-approval-rule-template
get-blob                                 | get-branch
get-comment                              | get-comment-reactions
get-comments-for-compared-commit         | get-comments-for-pull-request
get-commit                               | get-differences
get-file                                 | get-folder
get-merge-commit                         | get-merge-conflicts
get-merge-options                        | get-pull-request
get-pull-request-approval-states         | get-pull-request-override-state
get-repository                           | get-repository-triggers
list-approval-rule-templates             | list-associated-approval-rule-templates-for-repository
list-branches                            | list-pull-requests
list-repositories                        | list-repositories-for-approval-rule-template
list-tags-for-resource                   | merge-branches-by-fast-forward
merge-branches-by-squash                 | merge-branches-by-three-way
merge-pull-request-by-fast-forward       | merge-pull-request-by-squash
merge-pull-request-by-three-way          | override-pull-request-approval-rules
post-comment-for-compared-commit         | post-comment-for-pull-request
post-comment-reply                       | put-comment-reaction
put-file                                 | put-repository-triggers
tag-resource                             | test-repository-triggers
untag-resource                           | update-approval-rule-template-content
update-approval-rule-template-description | update-approval-rule-template-name
update-comment                           | update-default-branch
update-pull-request-approval-rule-content | update-pull-request-approval-state
update-pull-request-description          | update-pull-request-status
update-pull-request-title                | update-repository-description
update-repository-name                   | credential-helper
help
```

上記一覧を見ると、どうやら「list-repositories」が良さそうなので、こちらを実行してみます。

```
# aws codecommit list-repositories
{
    "repositories": [
        {
            "repositoryName": "xxxxx_test",
            "repositoryId": "xxxxx"
        }
    ]
}
```

aws cliからもCodeCommitにリポジトリが登録されたことが確認できました。
なお、ここまで一切、マネジメントコンソールは使用していません。
IaCらしい検証になっていると思います。

### IAMにアクセス権限を付与


### リポジトリ操作

ここからはgitの世界の話になってきます。
先程登録したリポジトリをローカルにクローンします。

```
# git clone codecommit::us-west-2://xxxxx_test
```

以降は必ずこの手順で、というわけでもないのですが、今回は、
  ・gitの初期設定として、メールアドレスと名前を設定、
  ・ダミーファイルの作成、
  ・ローカルリポジトリへの追加、
  ・コミット発行、
  ・リモートリポジトリ(CodeCommit)へプッシュ
という流れで検証を行ってみました。

```
# git config --global user.email "example@example.com"
# git config --global user.name "example"

# touch a.txt
# git add .
# git commit -m "first commit"
# git push origin master
```

## おわりに

今回はIaCらしく、最初から最後までGUIを使わずすべてコマンドで実行しました。

リポジトリといえば、gitHubやgitLabなどがありますが、そういうサービスを使ったり環境を構築してメンテナンスしたりということが不要なAWSのgitリポジトリのサービスのようだということが体感して理解できました。

また、リポジトリを作ってしまえば、あとはgitの経験があれば特に躓くことなく利用できることもわかりました。

以前、検証のために有志と自分のローカル環境にgitLabの環境を構築しました。
環境構築の経験ができたことは良かったのですが、資材を共有することはできません。
今回、AWSのCodeCommitを使ってみて、有志との検証はローカルのgitLabだけでなく、AWS CodeCommitも利用してみたくなりました。

今回はaws configureでawsにアクセスする事ができる前提で検証しましたが、これをAnsible Tower(AWX)と連携することができるかという新たな疑問が湧きました。

このあたりはまた有志と相談しつつ検証テーマを決めていきたいと思います。