サポート終了するAmazon Linuxのバージョンアップ移行対応(Terraform利用)

# 目的
もう間もなくとなりますが、2020年中にAmazon Linuxのサポート期間が切れてメンテナンスサポート期間に移行します。
https://aws.amazon.com/jp/blogs/news/update-on-amazon-linux-ami-end-of-life/

>メンテナンスサポート
2020 年 12 月 31 日を過ぎると Amazon Linux AMI には新たにメンテナンスサポート期間が設定されます (2023 年 6 月 30 日まで継続)。
この新たなメンテナンスサポート期間中は、Amazon Linux AMI には重要、重大なセキュリティアップデートだけが縮小パッケージセットとして提供されます。
ただし、新しい EC2 プラットフォームキャパシティーや AWS の新機能に対するサポートは保証されません。

本記事では、Amazon LinuxからAmazon Linux2に移行する時の手順と注意点をまとめます。

# 環境
今回の例は、以下のようなAmazon Linuxで稼働するEC2のバージョンアップになります。

* AMIは`Amazon Linux AMI 2018.03.0.20180508 x86_64 HVM GP2`
* AWSリソースは全体をterraformで管理
* 複数メンバーの公開鍵を登録し、sshでアクセス可能
* 外部からsshするためのEIPを持つ


# 移行
Amazon Linux2への移行は、**インプレースアップグレード(稼働中のシステムを直接アップグレードする手法)**はサポートされていないので、**リプレースアップグレード(稼働中のシステムと別にアップグレード済みシステムを用意して切り替える手法)**する必要があります。

よって、以下のような手順で移行します。

1. 現行のインスタンスと別にAmazon Linux2のAMIを使って新インスタンスを作成。
2. 一時的に2台を並行稼働した状態で、現行から公開鍵などの必要なデータを新インスタンスに移行。
3. IPを切り替える。
4. 現行インスタンスを削除し、新インスタンスのみ稼働。

データコピーが必要なため、現行と同じVPC、subnet、AZに新インスタンスを作成します。

![AL2_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/99c6ba27-d961-4eaa-c360-d8fada10a715.png)

## 事前確認
**Amazon LinuxとAmazon Linux2ではインストール可能なパッケージが違うので、移行が出来るか事前に確認が必要です。**
まずは現行のAmazon Linux上で、Amazon Linux2に移行する場合の影響を確認するプレアップグレードアシスタントを実行して影響を確認しておきます。

```bash
# プレアップグレードアシスタントをインストール
sudo yum install -y preupgrade-assistant preupgrade-assistant-al1toal2
# アシスタント実行
sudo preupg
```
詳細な実行結果は以下のようなHTMLファイルで出力されるので、内容を確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/72b6da59-1fb6-c6d6-1587-8ad63f98c884.png)
６項目のルールのチェック結果とスコアが表示されています。
ルールチェックについてはPythonに関して一件検査が必要だという結果が出ていますが、特に支障はないので移行可能と判断しました。


その他、公式ドキュメントで詳細な違いについて確認しておきます。
* [Amazon Linux 2 に関するよくある質問](https://aws.amazon.com/jp/amazon-linux-2/faqs/)

## 新インスタンスの作成
terraformでAWSリソースを管理しているので、現行インスタンスのmoduleである`ec2`をコピーし、`name`と`AMI`だけ変更して新インスタンス用moduleとして`ec2_new`を作成します。
backend.tfにAMI用のssm_parameterのdataを作成して、Amazon Linux 2の最新版を取得します。

```hcl:backend.tf
data "aws_ssm_parameter" "this" {
  name = "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"
}
```

```hcl:main.tf
module "ec2_new" {
  source = "../../../../../../modules/external/github/terraform-aws-modules/terraform-aws-ec2-instance"

  name          = "ec2_new_name"
  ami           = data.aws_ssm_parameter.this.value
  instance_type = "t3.nano"
  key_name      = var.ec2_key_name
  monitoring    = true

  vpc_security_group_ids = [
    data.terraform_remote_state.security_group.outputs.sg_internal_id,
    module.sg.this_security_group_id,
  ]

  subnet_id                   = element(data.terraform_remote_state.vpc.outputs.public_subnets, 0)
  disable_api_termination     = true
  associate_public_ip_address = true
  user_data                   = data.template_cloudinit_config.config.rendered
  iam_instance_profile        = "${title(var.app_name)}ec2_new_name"
```
`terraform apply`後、正しく新インスタンスが作成されていることを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/c495533f-67a1-704d-1412-73eab255ca45.png)


## データコピー
新インスタンスに割り当てられたPrivateIPを確認し、現行インスタンスから以下のデータをコピーします。

* /etc/sudoers：sudo可能ユーザや可能コマンドを管理
* /etc/passwd：ユーザとパスワードを管理
* /etc/shadow：各ユーザの暗号化されたパスワードを管理
* /etc/group：権限グル―プを管理         
* /etc/gshadow：権限グループの暗号化パスワードを管理
* /home：ユーザごとの公開鍵を含むローカルディレクトリ

### データコピー時の注意点
データコピーに際しては、**作業するユーザが権限を持たない、rootや他のユーザの所有しているディレクトリに対しても移行する必要**があります。
単純にscpでコピー元として/homeを指定しても、パーミッションエラーとなってコピーが出来ません。
そこで、以下の通りssh時にリモート先の/homeをtarで固めてローカルにコピーしてくるという方法を取りました。

```bash
# 新インスタンス側で実行する場合
ssh user@現行インスタンス "tar zxvf -C /home -" < /tmp
cp -a /tmp/home/user /home
```

/homeデータコピーが済むと、AWSが動的に割り当てたGrobalIPを指定して新インスタンスにssh出来るようになります。
この時に、**パーミッション相違や移行漏れファイルがないか**確認します。
各ユーザは既存のローカル秘密鍵を使い、現行インスタンスから新インスタンスにコピーした公開鍵を使って認証してsshする形になります。

## EIPの切り替え
既存のEIPを新インスタンスに付け替えます。
EIPのresorceで指定しているmoduleを`ec2`から`ec2_new`に変更して切り替えます。

```hcl:main.tf
# 変更後
resource "aws_eip" "this" {
  vpc      = true
  instance = element(module.ec2_new.id, 0)
}
```

`terraform plan`でEIPの割り当てインスタンスが切り替わることを確認しapplyします。

```bash
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  ~ update in-place
Terraform will perform the following actions:
  # aws_eip.this will be updated in-place
  ~ resource "aws_eip" "this" {
        association_id    = "eipassoc-0e291430b051514f9"
        domain            = "vpc"
        id                = "eipalloc-060bc8d30f11a933f"
      ~ instance          = "i-039fe23cd242331a7" -> "i-05c1fa53ee28cd971"
        network_interface = "eni-03180ae1d6eaeeeb9"
        private_dns       = "ip-xx-xx-xx-xx.ap-northeast-1.compute.internal"
        private_ip        = "xx.xx.xx.xx"
        public_dns        = "ec2-yy-yy-yy-yy.ap-northeast-1.compute.amazonaws.com"
        public_ip         = "zz.zz.zz.zz"
        public_ipv4_pool  = "amazon"
        tags              = {
            "Name" = "ec2"
        }
        vpc               = true
        timeouts {}
    }
Plan: 0 to add, 1 to change, 0 to destroy.
```

## 確認
EIPの切り替えが完了し、改めてsshしてみると以下のような警告メッセージが表示されます。

```bash

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:.
Please contact your system administrator.
Add correct host key in /Users/username/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /Users/username/.ssh/known_hosts:6
ECDSA host key for xx.xx.xx.xx has changed and you have requested strict checking.
Host key verification failed.
```

EIPが変わったことによる警告なので、`.ssh/known_hosts`の対象インスタンスの行を一度削除すればssh出来るようになります。


## 現行インスタンス削除

新インスタンスの作成時にコピー元にしたmoduleである`ec2`を削除します。
`terraform plan`で現行インスタンスのみが削除されることを確認してください。

現行インスタンス削除後、新インスタンス用につけたmodule名を`ec2_new`から`ec2`に戻して移行完了です。

## 参考
* [Amazon Linux2 プレアップグレードアシスタントをやってみた](
https://dev.classmethod.jp/articles/al1toal2assistant/)
* [/etc/passwd と /etc/groupの移行について](https://blog.serverworks.co.jp/migrate-password-related-files)
* [ssh経由でのtarによるフォルダの圧縮・解凍方法](https://orebibou.com/ja/home/201502/20150205_001/)
* [「SSHホスト鍵が変わってるよ！」と怒られたときの対処](https://qiita.com/hnw/items/0eeee62ce403b8d6a23c)