クラウドのリソースを最初からTerraformのような構成管理ツールを使って構築していくのは結構難しい。必要なリソースが何なのかもわからないし、構成自体を試行錯誤していきたいのに、その都度構成管理のファイルを修正し適応するとなると、構成管理ツールでの記述方法を調べる必要もあったり、時には使いたい機能がサポートされていなかったりする。最初の構成は手動で作成し、その後構成管理のファイルとして出力し、それを元に構成を作り直す方が効率的であるように思う。そんなツールがあるのかというと、もちろんある。Terraformの場合はTerraformerというツールを使うことで、これを実現できる。
今回はこのTerraformerを使って既存のAWS上のリソースをTerraformのファイルとして出力する。
https://github.com/GoogleCloudPlatform/terraformer
brew install terraformer
Terraformerの実行にはTerraformのプロジェクトが必要になるため、予め作成する。
terraform init
init.tf
provider "aws" {}
AWSのリソースを指定して、terrafomerを実行する。
terraformer import aws --resources=dynamodb --regions=ap-northeast-1 --profile=example
Process vterm<3> finished
2023/07/06 19:06:26 aws importing region ap-northeast-1
2023/07/06 19:06:31 aws importing... dynamodb
2023/07/06 19:06:31 aws done importing dynamodb
2023/07/06 19:06:31 Number of resources for service dynamodb: 1
2023/07/06 19:06:31 Refreshing state... aws_dynamodb_table.tfer--XXXXXXXXXXXXXX/07/06 19:06:31 Filtered number of resources for service dynamodb: 1
2023/07/06 19:06:31 aws Connecting....
2023/07/06 19:06:31 aws save dynamodb
2023/07/06 19:06:31 aws save tfstate for dynamodb
tree generated
generated `-- aws `-- dynamodb |-- dynamodb_table.tf |-- outputs.tf |-- provider.tf `-- terraform.tfstate 2 directories, 4 files
完了すると generated
ディレクトリが作成され、以下のように tf
ファイルと tfstate
ファイルが作成される。
AWSで指定可能なリソース
--resources
オプションで指定可能なリソースは、terraformで指定可能なリソースとなるのかと思っていたけれど、そうでもなかった。これはどうやって確認できるのだろうと持っていたが、usageに確認方法が記述されていた。 terraformer import aws list
を実行する事で、指定可能なリソースを確認できる。
--resources
はカンマ区切りで複数指定でき、ワイルドカードも指定できる。また、一部分だけ除外したい場合は --exclude
で除外指定できる。このあたりはREADMEに記述されている。
terraformer import aws list
accessanalyzer |
acm |
alb |
api_gateway |
appsync |
auto_scaling |
batch |
budgets |
cloud9 |
cloudformation |
cloudfront |
cloudhsm |
cloudtrail |
cloudwatch |
codebuild |
codecommit |
codedeploy |
codepipeline |
cognito |
config |
customer_gateway |
datapipeline |
devicefarm |
docdb |
dynamodb |
ebs |
ec2_instance |
ecr |
ecrpublic |
ecs |
efs |
eip |
eks |
elastic_beanstalk |
elasticache |
elb |
emr |
eni |
es |
firehose |
glue |
iam |
igw |
iot |
kinesis |
kms |
lambda |
logs |
media_package |
media_store |
msk |
nacl |
nat |
opsworks |
organization |
qldb |
rds |
redshift |
resourcegroups |
route53 |
route_table |
s3 |
secretsmanager |
securityhub |
servicecatalog |
ses |
sfn |
sg |
sns |
sqs |
ssm |
subnet |
swf |
transit_gateway |
vpc |
vpc_peering |
vpn_connection |
vpn_gateway |
waf |
waf_regional |
wafv2_cloudfront |
wafv2_regional |
workspaces |
xray |
権限
Terraformerでリソースを取得するには各種リソースの一覧を取得する権限が必要になる。強い権限を使っても良さそうではあるけれど、できることならその時に必要な最低限の権限を使って操作を行いたい。リソースのインポートでは、基本的には読み取りしか発生しないはずであり、その権限のみで良いはず。READMEにも同様の記述がある。権限が不足している場合は、API呼び出しでエラーするため権限を付与する必要がある。
例えばS3に関連するリソースをTerraformerで取得する場合、次のような権限が必要になる。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Statement1",
"Effect": "Allow",
"Action": [
"s3:GetAccelerateConfiguration",
"s3:GetBucketAcl",
"s3:GetBucketCors",
"s3:GetBucketLocation",
"s3:GetBucketLogging",
"s3:GetBucketObjectLockConfiguration",
"s3:GetBucketPolicy",
"s3:GetReplicationConfiguration",
"s3:GetBucketRequestPayment",
"s3:GetBucketTagging",
"s3:GetBucketVersioning",
"s3:GetBucketWebsite",
"s3:GetEncryptionConfiguration",
"s3:GetLifecycleConfiguration",
"s3:GetReplicationConfiguration",
"s3:ListAllMyBuckets",
"s3:ListBucket"
],
"Resource": [
"*"
]
}
]
}
この権限を持つIAMポリシーを作成しユーザーにアタッチし、以下のコマンドを実行するとエラーせずリソースを取得する事ができた。
terraformer import aws --regions=ap-northeast-1 --resources=s3 --regions=ap-northeast-1 --profile=fish --verbose
この権限は取得だけを考えているため、これを元にTerraformを修正し terraform apply
などは当然できない。以下にいくつかのサービスに対してTerraformerを実行する時に必要な権限を掲載する。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Statement1",
"Effect": "Allow",
"Action": [
"dynamodb:DescribeContinuousBackups",
"dynamodb:DescribeTable",
"dynamodb:DescribeTimeToLive",
"dynamodb:ListTables",
"dynamodb:ListTagsOfResource"
],
"Resource": [
"*"
]
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Statement1",
"Effect": "Allow",
"Action": [
"ecr:DescribeImages",
"ecr:DescribePullThroughCacheRules",
"ecr:DescribeRegistry",
"ecr:DescribeRepositories",
"ecr:GetLifecyclePolicy",
"ecr:GetRepositoryPolicy",
"ecr:ListImages",
"ecr:ListTagsForResource"
],
"Resource": [
"*"
]
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Statement1",
"Effect": "Allow",
"Action": [
"lambda:GetFunctionConfiguration",
"lambda:GetPolicy",
"lambda:ListEventSourceMappings",
"lambda:ListFunctionEventInvokeConfigs",
"lambda:ListFunctionUrlConfigs",
"lambda:ListFunctions",
"lambda:ListFunctionsByCodeSigningConfig"
],
"Resource": [
"*"
]
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Statement1",
"Effect": "Allow",
"Action": [
"sqs:GetQueueAttributes",
"sqs:ListDeadLetterSourceQueues",
"sqs:ListQueueTags",
"sqs:ListQueues"
],
"Resource": [
"*"
]
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Statement1",
"Effect": "Allow",
"Action": [
"ecs:ListServices",
"ecs:ListTaskDefinitions",
"ecs:ListClusters",
"ecs:ListTaskDefinitionFamilies",
"ecs:DescribeClusters",
"ecs:DescribeServices",
"ecs:DescribeTaskDefinition",
"ecs:DescribeCapacityProviders"
],
"Resource": [
"*"
]
}
]
}
IAMはとても複雑だがCloudTrailなどから、そのユーザーが呼び出したイベントを取得できるので、そこから権限を振ると良い。ただし罠もあって、権限の名前がイベントの名前とは限らない。今回だと s3:GetEncryptionConfiguration
権限は、実際に呼び出されたイベントは GetBucketEncryption
だったりする。このあたりの辻褄を地道に合わせた。これらの操作を上手く行う方法はないのだろうか。
https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazons3.html