最新 追記

雑記帳


2015-07-03 (Fri) [長年日記]

[AWS] AWS CLIを使ってELBのサーバ証明書を更新する

証明書の有効期限が切れるなどで、ELBの証明書を更新するときは、次のようにすると良い。

  1. 新しい証明書をアップロードする
  2. アップロードした証明書のARNを取得する
  3. ELBに証明書を関連付ける

順を追って詳しくみていく。

新しい証明書をアップロードする

証明書を更新するということなので、使うAPIは update-server-certificate かと思いきや、これは証明書の名前やパスを変更するためのAPIであり、既存の証明書の入れ替えに使えるわけではない。

ということで、既存の証明書とは重複しない名前を使って、 upload-server-certificate でアップロードする。

% aws iam upload-server-certificate \
    --server-certificate-name manage.example.com.20150703 \
    --certificate-body file://manage.example.com.crt \
    --private-key file://manage.example.com.key
{
    "ServerCertificateMetadata": {
        "ServerCertificateId": "Axxxxxxxxxxxxxxxxxxxx",
        "ServerCertificateName": "manage.example.com.20150703",
        "Expiration": "2015-07-17T12:30:37Z",
        "Path": "/",
        "Arn": "arn:aws:iam::012345678901:server-certificate/manage.example.com.20150703",
        "UploadDate": "2015-07-03T07:41:50.230Z"
    }
}

--server-certificate-nameには、任意の名前を指定する。 --certificate-bodyには、証明書のファイルを渡す。 --private-keyには、暗号化されていない秘密鍵のファイルを渡す。 中間証明書がある場合は、同様に--certificate-chainを指定する。

file://... という指定の仕方について。カレントディレクトリにあるファイルは、file://fileと指定すれば良い。ルートからの絶対パスを渡す場合は、file:///path/to/fileとする。スラッシュの数に注意する。これは、AWS CLI全般で同じ。

アップロードした証明書のARNを取得する

ELBに証明書を関連付けるには、SetLoadBalancerListenerSSLCertificate APIを使う。

パラメータに、SSLCertificateIdというのがあるので、GetServerCertificate APIで取得できる値にある、ServerCertificateIdを渡せばいいの方思いきや、そうではない。SSLCertificateIdには、ARNを渡す。

ということで、GetServerCertificate APIを使って、ARNを取得する。

% aws iam get-server-certificate \
    --server-certificate-name manage.example.com.20150703 \
    --query "ServerCertificate.ServerCertificateMetadata.Arn"
"arn:aws:iam::012345678901:server-certificate/manage.example.com.20150703"

ELBに証明書を関連付ける

最後に、アップロードした証明書と、既存のELBのリスナーに関連付ける。 リスナーの指定は、LoadBalancerPortに対して、リスナーがリッスンしているポート番号を指定する。通常は、443だろう。

% aws elb set-load-balancer-listener-ssl-certificate \
    --load-balancer-name manage \
    --load-balancer-port 443 \
    --ssl-certificate-id arn:aws:iam::012345678901:server-certificate/manage.example.com.20150703

成功した場合は、特に出力はない。

結果の確認

実際に設定されているかどうか、確認してみる。

% aws elb describe-load-balancers \
    --query 'LoadBalancerDescriptions[?LoadBalancerName==`manage`].ListenerDescriptions[].Listener.SSLCertificateId'
[
    "arn:aws:iam::012345678901:server-certificate/manage.example.com.20150703"
]

問題なく設定されていた。

[AWS] ELBに設定されている証明書を削除するとInvalid-Certificateになる

AWS CLIで、サーバ証明書を削除するには、delete-server-certificate を使う。ELBに設定されている証明書を削除したら、どうなるだろうかと思って試しにやってみた。

予想では、エラーになるのではないか。

% aws iam delete-server-certificate --server-certificate-name manage.example.com.20150703

特にエラーが出なかった。削除されたようだ。

ELBの状態はどうなるんだろうか。

% aws elb describe-load-balancers --query 'LoadBalancerDescriptions[?LoadBalancerName==`manage`].ListenerDescriptions[]'
[
    {
        "Listener": {
            "InstancePort": 80,
            "LoadBalancerPort": 80,
            "Protocol": "HTTP",
            "InstanceProtocol": "HTTP"
        },
        "PolicyNames": []
    },
    {
        "Listener": {
            "InstancePort": 80,
            "SSLCertificateId": "Invalid-Certificate",
            "LoadBalancerPort": 443,
            "Protocol": "HTTPS",
            "InstanceProtocol": "HTTP"
        },
        "PolicyNames": [
            "AWSConsole-SSLNegotiationPolicy-manage-1435909598260"
        ]
    }
]

"SSLCertificateId": "Invalid-Certificate" となるようだ。なるほど。

新しい証明書を有効にした後、古い証明書を削除しようとして、間違って新しい証明書を消さないように注意しないと。


2015-07-05 (Sun) [長年日記]

[AWS] ELBに登録された証明書を削除できなくなる

先日、「ELBに設定されている証明書を削除するとInvalid-Certificateになる」という記事を書いた。

ここでは、Invalid-Certificateになると書いたが、実は削除が失敗することがあった。 下記は、その時の、CloudTrailのログから、エラー情報を抜粋したものである。

"errorCode": "DeleteConflictException",
"errorMessage": "Certificate: Axxxxxxxxxxxxxxxxxxxx is currently in use by arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:loadbalancer/manage. Please remove it first before deleting it from IAM.",

証明書がELBに使われているので、まずは外してから削除せよ、とある。

これについて、AWSサポートに問い合わせしたところによると、運用中のELBから、誤って証明書を削除してしまうという事故が結構あり、その事故防止の観点からの仕様変更のようである。2015-07-02前後に順次適用されたようだ。

昨日書いた記事では削除は成功している。上記のエラーは、実は記事を書いた以前に発生したものなので、環境によっては仕様変更が適用されていたりいなかったりするようである。

ただ、仕様変更があったことは間違いないので、今後は、ELBに登録されている証明書は、削除できないと理解しておいた方が良い。

2015-07-24追記: どうやら、AWSとしては、仕様変更ではなくてバグ修正という認識であるようだ。そのような場合は、正式なアナウンスは行わないらしい。


2015-07-14 (Tue) [長年日記]

[AWS] セキュリティグループのアクセス許可IPアドレスを変更するツールを作った

オフィスを引っ越ししたり、踏み台として使っているサーバが変更になったりなどで、セキュリティグループでアクセス許可設定をしていたIPアドレスが変更になる、ということがたまにある。

セキュリティグループの管理といえば、Piculetが定番である。ExportしたDSLをgitなどで管理することができる、非常に便利なツールである。しかし、多数のAWSアカウントとリージョンに対して、バッチ的に変更を行いたいという場合には、ちょっと工夫が必要になる。

もう少しお手軽に更新したい、という声があったので作ってみたのがこちら。

対象となるリージョンに存在するセキュリティグループすべてをチェックして、指定されたCIDRを検索する。そして、すべてを置き換え対象となるCIDRで置換を行うというもの。例えば、以下のように実行する。

$ sgupdater update --from-cidr 192.0.2.0/24 --to-cidr 198.51.100.0/24

バッチ的に複数の環境に適用するなら、こちらの方が簡単にできるかと思う。

ちなみに、sgupdaterは、内部的にはPiculetを使っている。Piculetは本来、ライブラリ的に使えるように設計されていないのだが、ちょっと無理やり使わせてもらっている。感謝します。


2015-07-15 (Wed) [長年日記]

[Linux] 独自のルートCA証明書を追加する方法(Ubuntu, CentOS 7)

社内に立てたCAの証明書をLinuxに入れる必要があったので方法を調べたのでまとめる。 UbuntuとCentOS 7は、それぞれ同じような方法で実施できる。

CentOS 7

/usr/share/pki/ca-trust-source/anchors に、CA証明書を配置する。

$ sudo cp mycacert.crt /usr/share/pki/ca-trust-source/anchors

update-ca-trustコマンドを実行する。

$ sudo update-ca-trust extract

Ubuntu

/usr/share/ca-certificates に、CA証明書を配置する。

$ sudo cp mycacert.crt /usr/share/ca-certificates

/etc/ca-certificates.confに、/usr/share/ce-certificetsからの相対パスで、ファイル名を追記する。

$ sudo vim /etc/ca-certificats.conf

update-ca-certificetsを実行する。

$ sudo update-ca-certificates

2015-07-22 (Wed) [長年日記]

[AWS] AWS CLIではじめるVPC Flow Logs

VPC内の通信のログを取ることができる、VPC Flow Logsを使ってみたいという要望があったので、設定してみる。

まずは、ドキュメントを参照する。

ドキュメントによると、ログ自体はCloudWatch Logsに格納されるようになっており、それに対するアクセス権限は、IAM Roleを使って管理をするようだ。

ということで、設定してみる。

AWS CLIの確認

AWS CLIがVPC Flow Logsに対応したのは、1.7.33である。手元のAWS CLIのバージョンを確認する。

% aws --version
aws-cli/1.7.39 Python/2.7.6 Darwin/14.4.0

1.7.39は現時点の最新版なので、VPC Flow Logsは使えるようになっている。

% aws ec2 help |grep flow
       o create-flow-logs
       o delete-flow-logs
       o describe-flow-logs

AWS CLIの準備はできているので、次に進む。

IAM Roleの作成

VPC Flow Logsでは、IAM Roleを割り当てる必要があるので、まずはIAM Roleを作成する。

ところで、AWS Management ConsoleでしかIAMを触ったことがない向きは、ぜひ一度はAWS CLIで作成してみることをお勧めする。その理由は、AWS Management Consoleは簡単に扱えるようにするため、詳細を結構隠蔽しているからだ。

IAM RoleをVPC Flow Logsで使えるようにするには、下記のステップを踏まないといけない。

  • Assume Role Policy Documentを用意する
  • IAM Roleを作成する
  • Instance Profileを作成する
  • IAM RoleとInstance Profileを関連付ける
  • PolicyをRoleに関連付ける

順番に見ていこう。

Assume Role Policy Documentを用意する

作成するIAM Roleの種類はvpc-flow-logsとなるため、下記のAssume Role Policy Documentを使う。

{
  "Version": "2012-10-17",
    "Statement": {
      "Effect": "Allow",
      "Principal": {
        "Service": "vpc-flow-logs.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
}
IAM Roleを作成する

create-roleを実行する際に、このポリシーを設定する。

% aws iam create-role --role-name flowlogs \
  --assume-role-policy-document '{"Version": "2012-10-17","Statement":{"Effect": "Allow","Principal":{"Service":"vpc-flow-logs.amazonaws.com"},"Action":"sts:AssumeRole"}}'

実行が成功すると、下記のような結果が返る。

{
  "Role": {
    "AssumeRolePolicyDocument": {
      "Version": "2012-10-17",
        "Statement": {
          "Action": "sts:AssumeRole",
          "Effect": "Allow",
          "Principal": {
            "Service": "vpc-flow-logs.amazonaws.com"
          }
        }
    },
      "RoleId": "xxxxxxxxxxxxxxxxxxxxx",
      "CreateDate": "2015-07-21T09:44:40.192Z",
      "RoleName": "flowlogs",
      "Path": "/",
      "Arn": "arn:aws:iam::000000000000:role/flowlogs"
  }
}
Instance Profileを作成する

これは余談だが、AWS Management Consoleを使っていると、Instance Profileについて意識する必要はない。AWS Management Consoleは、Instance Profileを独立したリソースとして扱わないからだ。EC2を対象としたIAM Roleの情報を表示すると、Instance ProfileのARNが表示されるのか確認できる。

AWS Management Consoleは、IAM RoleとInstance Profileを同時に取り扱う(ライフタイムが同一となる)。また、全く同じ名前であることを前提としているようなので注意が必要となる。APIでは個別に取り扱うことができるのだが、IAM RoleとInstance Profileが別の名前になっていると、AWS Management Console上では、IAM Roleを削除したりできなくなってしまう。そういった場合は、AWS CLIなどを使って、直接APIを使わないといけない。

ということで、Instance Profileを作成する。前述のような問題があるため、IAM Roleと全く同じ名前で作成する。

% aws iam create-instance-profile --instance-profile-name flowlogs

作成に成功すると、下記のような結果が返る。

{
    "InstanceProfile": {
        "InstanceProfileId": "xxxxxxxxxxxxxxxxxxxxx",
        "Roles": [],
        "CreateDate": "2015-07-21T10:13:30.953Z",
        "InstanceProfileName": "flowlogs",
        "Path": "/",
        "Arn": "arn:aws:iam::000000000000:instance-profile/flowlogs"
    }
}
IAM RoleとInstance Profileを関連付ける

IAM RoleとInstance Profileができたので、それぞれ関連付ける。

% aws iam add-role-to-instance-profile --instance-profile-name flowlogs --role-name flowlogs

成功した場合は、特に何も表示されない。

PolicyをRoleに関連付ける

VPC Flow Logsが、CloudWatch Logsにアクセスのに必要な権限を付与する。ドキュメントに記載のある権限を付与すれば良い。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents",
        "logs:DescribeLogGroups",
        "logs:DescribeLogStreams"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}

ポリシーを付与する。

% aws iam put-role-policy --role-name flowlogs --policy-name flowlogs --policy-document '{ "Version": "2012-10-17", "Statement": [ { "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents", "logs:DescribeLogGroups", "logs:DescribeLogStreams" ], "Effect": "Allow", "Resource": "*" } ] }'

こちらも、成功した場合はなにも出力されない。

以上で、IAM Roleの設定が完了した。ちなみに、AWS Management Consoleを使った場合は、VPC Flow Logsを作成するときに、この辺りの設定をまとめてやってくれるようになっている。

CloudWatch Logsのグループを作成する

VPC Flow Logsの出力先となる、CloudWatch Logsのグループを作成する。

% aws logs create-log-group --log-group-name flow-logs

成功した場合の出力はない。結果を確認する。

% aws logs describe-log-groups
{
    "logGroups": [
        {
            "arn": "arn:aws:logs:ap-northeast-1:000000000000:log-group:flow-logs:*",
            "creationTime": 1437472183580,
            "metricFilterCount": 0,
            "logGroupName": "flow-logs",
            "storedBytes": 0
        }
    ]
}
VPC Flow Logsの作成

仕上げに、VPC Flow Logsを作成する。

% aws --profile iret ec2 create-flow-logs \
  --resource-ids vpc-deadbeaf \
  --resource-type VPC \
  --traffic-type ALL \
  --log-group-name flow-logs \
  --deliver-logs-permission-arn arn:aws:iam::000000000000:role/flowlogs

ここでは、対象をVPC全体とし、VPC IDをパラメータに渡している。d

--resource-typeをVPCとしている。対象はVPCだけでなく、Elastic Network Interface (ENI) にしたり、Subnetにしたりできる。

--traffic-typeは、ロギング対象となるトラフィックの種類を指定する。ACCEPT, REJECT, ALLがしていできる。ここではALLとしている。

ちなみに、--traffic-typeと--resource-typeは、ともにすべて大文字でないと失敗するようだ。

--deliver-logs-permission-arnは、分かりづらいが、先ほど作成したIAM RoleのARNを指定する。

実行した結果は、以下のような出力が得られる。

{

   "Unsuccessful": [],
   "FlowLogIds": [
       "fl-deadbeaf"
   ],
   "ClientToken": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

}

失敗した場合は、Unsuccessfulに理由が入るようだ。今回は何も含まれていないので、成功したということになる。

Log Streamsの確認

これで準備ができたので、あとはログが取得できるようになる。設定した直後はすぐにデータが流れてこないかと思うが、数分待てば出てくると思う。

先ほどは、Log Groupしか作成していないが、VPC Flow Logsが自動的にLog Streamを作成して、そこにログが入るようだ。ということで、Log Streamの確認をする。

% aws --profile iret logs describe-log-streams --log-group-name flow-logs

--log-group-nameに、作成したLog Groupの名前を渡す。Log Streamができていれば、下記のような出力になる。

{
    "logStreams": [
        {
            "firstEventTimestamp": 1437533334000,
            "lastEventTimestamp": 1437533881000,
            "creationTime": 1437533963999,
            "uploadSequenceToken": "49545657805925472387080468314713352704393428876698583762",
            "logStreamName": "eni-deadbeaf-all",
            "lastIngestionTime": 1437533964445,
            "arn": "arn:aws:logs:ap-northeast-1:000000000000:log-group:flow-logs:log-stream:eni-0081af59-all",
            "storedBytes": 0
        },
        {
            "firstEventTimestamp": 1437533370000,
            "lastEventTimestamp": 1437533854000,
            "creationTime": 1437534000225,
            "uploadSequenceToken": "49545657805657863444698057630133068269334483145861366802",
            "logStreamName": "eni-baadf00d-all",
            "lastIngestionTime": 1437534000659,
            "arn": "arn:aws:logs:ap-northeast-1:000000000000:log-group:flow-logs:log-stream:eni-04833872-all",
            "storedBytes": 0
        },
...

LogStreamNameを見ると、ENI単位でLog Streamが作成され、ログが格納されるようだ。実際に格納されているログを見てみよう。

% aws logs get-log-events --log-group-name flow-logs --log-stream-name eni-deadbeaf-all --limit 1
{
    "nextForwardToken": "f/32058076794435842183738125314793503818359848154310770799",
    "events": [
        {
            "ingestionTime": 1437533964445,
            "timestamp": 1437533881000,
            "message": "2 000000000000 eni-deadbeaf 10.0.2.7 10.0.132.91 59163 3306 6 29 2438 1437533881 1437533932 ACCEPT OK"
        }
    ],
    "nextBackwardToken": "b/32058076794435842183738125314793503818359848154310770799"
}

--limit 1として、一行だけ取得している。messageの部分に、スペース区切りでログが出力されている。それぞれの値の意味は、version, account-id, interface-id, srcaddr, dstaddr, srcport, dstport, protocol, packets, bytes, start, end, action, log-statusとなる。

このログは、FlowLogs version 2が取得したデータで、AWSアカウント000000000000の、eni-deadbeafにおいて、10.0.2.7から10.0.132.91に、ポート59163から、3306ポートに、TCPで、29パケット、2438 byets, UNIX Timeで、1437533881 から 1437533932 までの間に送信され、ACCEPTされた。ログの取得も成功した、ということが示されている。実際のデータの中身については記録されていない。

詳細は、ドキュメントを参照のこと。

ENIのリストを見ていて気がついたのだが、EC2はもとより、RDS、ELB、Directory Service、WorkspacesなどもENIがあるため、ログが取得できるようだ。

まとめ

VPC Flow Logsを使うと、VPC内にあるEC2だけでなく、ENIが存在しているサービスすべてについて、ログを取得することができるので、とても便利だ。特に、REJECTのログも取得できるので、セキュリティグループでブロックされた通信の状態をみれる。トラブルシュートが捗ると思われる。