用Terraform创建lambda运行python定期自动更新AWS安全组
背景
基础设施即代码IaC,是一种更为优雅的管理云上基础设施的方式。
我这里使用开源的terraform,创建和管理AWS中的serverless运行代码的服务lambda,运行python脚本,获取最新的Cloudflare IP网段,并更新到目标安全组中;
然后通过CloudWatch的EventBridge,定期的触发该lambda。
这个过程中,还需要通过terraform创建必要的IAM role和IAM policy。
操作步骤
准备步骤
确保当前环境已安装terraform,并创建指定文件夹并进入,然后创建main.tf文件并准备写入配置文件。
mkdir terraform-experiment3
cd terraform-experiment3
vim main.tf
创建lambda
在main.tf中,通过如下代码创建lambda
provider "aws" {
# access_key and secret_key can be excluded if you
# have your creds setup in ~/.aws
access_key = "AKIA********NU5"
secret_key = "leVIwk********************dwx/a"
region = "ap-east-1"
}
# 创建名为"terraform-managed-lambda_AutoUpdateSG4Cloudflare"的lambda
resource "aws_lambda_function" "terraform_lambda_AutoUpdateSG4Cloudflare" {
function_name = "terraform-managed-lambda_AutoUpdateSG4Cloudflare"
filename = "cf-security-group-update.zip"
handler = "cf-security-group-update.lambda_handler"
role = "${aws_iam_role.iam_lambda_AutoUpdateSG4Cloudflare.arn}"
runtime = "python3.9"
timeout ="15"
environment {
variables = {
PORTS_LIST = "443"
SECURITY_GROUP_ID = "sg-06dc9f9cfd836b97f"
UPDATE_IPV6 = "0"
}
}
}
这里cf-security-group-update.zip来自https://github.com/johnmccuk/cloudflare-ip-security-group-update/blob/master/cf-security-group-update.py 压缩为zip文件,并上传至当前terraform运行服务器的terraform-experiment3文件夹下。
环境变量中的SECURITY_GROUP_ID 是已经创建好的安全组,这部分安全组的创建尚未纳入terraform管理,等其他功能都验证完毕后,之后可以考虑用terraform创建该安全组。
handler = “cf-security-group-update.lambda_handler” 代表cf-security-group-update这个文件下的lambda_handler为该lambda函数的入口点,它告诉 Lambda 在哪里开始执行代码。
![](https://yushuoxin.online/wp-content/uploads/2023/11/image-20-1024x724.png)
handler 这部分完成配置后,在AWS控制台对应配置位置如下。
![](https://yushuoxin.online/wp-content/uploads/2023/11/image-30-1024x536.png)
创建IAM执行角色
在main.tf中,通过如下代码创建名为”iam_lambda_AutoUpdateSG4Cloudflare”的IAM执行角色,并创建信任关系
#创建名为"iam_lambda_AutoUpdateSG4Cloudflare"的IAM执行角色,并创建信任关系
resource "aws_iam_role" "iam_lambda_AutoUpdateSG4Cloudflare" {
name = "iam_lambda_AutoUpdateSG4Cloudflare"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
上述指令生成的内容,在AWS控制台如下所示。
![](https://yushuoxin.online/wp-content/uploads/2023/11/image-17.png)
创建IAM Policy策略
在main.tf中,通过如下代码创建两个policy:
- policy1,添加更新安全组必要的权限,并绑定到当前IAM iam_lambda_AutoUpdateSG4Cloudflare上;
- policy2,添加lambda执行的基本权限,并绑定到当前IAM iam_lambda_AutoUpdateSG4Cloudflare上;
# 创建policy1,添加更新安全组必要的权限,并绑定到当前IAM iam_lambda_AutoUpdateSG4Cloudflare上;
data "aws_iam_policy_document" "lambda_policy_1" {
statement {
effect = "Allow"
actions = [
"ec2:AuthorizeSecurityGroupIngress",
"ec2:RevokeSecurityGroupIngress",
"ec2:DescribeSecurityGroups",
"s3:GetBucketPolicyStatus",
"s3:PutBucketPolicy",
"s3:GetBucketPolicy"
]
resources = [
"*"
]
}
}
resource "aws_iam_policy" "lambda_policy_1" {
name = "Policy-AutoUpdateSG4Cloudflare"
description = "Policy for Lambda execution"
policy = data.aws_iam_policy_document.lambda_policy_1.json
}
resource "aws_iam_role_policy_attachment" "Policy-AutoUpdateSG4Cloudflare" {
role = aws_iam_role.iam_lambda_AutoUpdateSG4Cloudflare.name
policy_arn = aws_iam_policy.lambda_policy_1.arn
}
# 创建policy2,添加lambda执行的基本权限,并绑定到当前IAM iam_lambda_AutoUpdateSG4Cloudflare上;
data "aws_iam_policy_document" "lambda_policy_2" {
statement {
effect = "Allow"
actions = [
"logs:CreateLogGroup"
]
resources = [
"arn:aws:logs:*"
]
}
statement {
effect = "Allow"
actions = [
"logs:CreateLogStream",
"logs:PutLogEvents"
]
resources = [
"arn:aws:logs:*"
]
}
}
resource "aws_iam_policy" "lambda_policy_2" {
name = "Policy-AWSLambdaBasicExecutionRole"
description = "Policy for Lambda execution"
policy = data.aws_iam_policy_document.lambda_policy_2.json
}
resource "aws_iam_role_policy_attachment" "Policy-AWSLambdaBasicExecutionRole" {
role = aws_iam_role.iam_lambda_AutoUpdateSG4Cloudflare.name
policy_arn = aws_iam_policy.lambda_policy_2.arn
}
创建后,AWS控制台可见配置如下图。
![](https://yushuoxin.online/wp-content/uploads/2023/11/image-18.png)
![](https://yushuoxin.online/wp-content/uploads/2023/11/image-19.png)
创建lambda触发器
这部分配置,我参考了文章https://www.codenong.com/44287186/。
在main.tf中,通过如下代码创建触发lambda的触发器,用Cloudwatch的EventBridge周期性触发lambda运行。
这部分代码还配置了Cloudwatch Events运行Lambda所必需的权限。
#创建触发lambda的触发器,用Cloudwatch的EventBridge周期性触发lambda运行
resource"aws_cloudwatch_event_rule""EventBridge_Rule_1minOR1day" {
name ="Rule-CloudwatchEventTriggerLambda_1minOR1day"
description ="desc"
schedule_expression ="cron(* * * * ? *)"
# 每分钟一次 "cron(* * * * ? *)"
# 每小时一次 "cron(0 * * * ? *)"
# 每天一次 "cron(0 0 * * ? *)"
}
resource"aws_cloudwatch_event_target""daily_target" {
rule ="${aws_cloudwatch_event_rule.EventBridge_Rule_1minOR1day.name}"
arn ="${aws_lambda_function.terraform_lambda_AutoUpdateSG4Cloudflare.arn}"
}
data"aws_caller_identity""current" {
# account_id = "118045904350"
}
resource"aws_lambda_permission""allow_cloudwatch" {
statement_id ="AllowExecutionFromCloudWatch"
action ="lambda:InvokeFunction"
function_name ="${aws_lambda_function.terraform_lambda_AutoUpdateSG4Cloudflare.function_name}"
principal ="events.amazonaws.com"
source_account ="${data.aws_caller_identity.current.account_id}"
source_arn ="${aws_cloudwatch_event_rule.EventBridge_Rule_1minOR1day.arn}"
}
上述代码中,account_id不需要自己填写,terraform会自己读取账号参数,所以我这里注释掉了。
schedule_expression 的语法可参考如下链接
https://docs.aws.amazon.com/lambda/latest/dg/services-cloudwatchevents-expressions.html
我这里添加了每分钟、每小时和每天的语法注释,可按需使用。
用terraform创建资源
上述所有代码都写入main.tf文件中后,就可以运行
terraform init
terraform apply
来创建必要的资源了。
运行printout截图如下。
![](https://yushuoxin.online/wp-content/uploads/2023/11/image-21.png)
![](https://yushuoxin.online/wp-content/uploads/2023/11/image-22.png)
![](https://yushuoxin.online/wp-content/uploads/2023/11/image-23.png)
![](https://yushuoxin.online/wp-content/uploads/2023/11/image-24.png)
![](https://yushuoxin.online/wp-content/uploads/2023/11/image-25.png)
功能验证
完成配置后,可登陆AWS控制台查看lambda等相关资源是否都正常创建了。
然后进入目标安全组,删除所有当前入站规则,等待1分钟后(当前测试环境,我配置的触发频率为1分钟一次),可以刷新页面,确认安全组策略可自动添加上。
![](https://yushuoxin.online/wp-content/uploads/2023/11/image-26.png)
还可到lambda页面的监控页中,点击“查看CloudWatch Logs”,查看相关log。
![](https://yushuoxin.online/wp-content/uploads/2023/11/image-27-1024x715.png)
![](https://yushuoxin.online/wp-content/uploads/2023/11/image-28-1024x705.png)
![](https://yushuoxin.online/wp-content/uploads/2023/11/image-29.png)
通过上述验证,可见自动更新安全组的功能,可以正常实现。
总结
通过上面的配置,我们成功实现了,通过terraform的声明式的方式,创建了lambda函数,并创建了必要的IAM role和policy,以及lambda的trigger,从而实现:
定期触发lambda,运行python脚本,获取最新的Cloudflare IP网段,并更新到目标安全组中。
后续计划
上面的配置中,安全组的创建是手动完成的,还没有纳入terraform的管理。
这部分等未来有时间,可以把安全组的创建也纳入terraform管理。
2023年11月23日22:06:41更新,完成了上述的后续计划。
在main.tf中,通过如下代码创建名为”SG-Cloudflare-AutoUpdate-terraform”的安全组,并设置出站规则为全部放通。
# 创建名为"SG-Cloudflare-AutoUpdate-terraform"的安全组
resource "aws_security_group" "sg-terraform" {
name = "SG-Cloudflare-AutoUpdate-terraform"
description = "SG-Cloudflare-AutoUpdate managed by terraform"
# 允许所有出站流量
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
然后把之前代码中 SECURITY_GROUP_ID 的部分,改为
SECURITY_GROUP_ID = aws_security_group.sg-terraform.id
即可完成:
新建安全组并纳入terraform管理;
通过上述lambda代码更新该安全组的入站规则。
发表回复