如何用Terraform正确配置AWS Elastic Beanstalk ALB默认监听器?
我在用Terraform配置Elastic Beanstalk环境时,想把ALB的默认80端口监听器转发到名为"redirect"的进程(而非默认的"default"进程)。该监听器采用HTTP协议,本不需要SSL配置,但应用配置时AWS持续报错:
Updating Load Balancer listener ... failed Reason: Resource handler returned message: "SSL policy cannot be empty"
我通过aws_elastic_beanstalk_configuration_template创建配置模板并关联到环境,尝试将SSLPolicy和SSLCertificateArns设为空字符串、null或不配置,都会触发上述错误;如果设置实际SSL值,AWS又提示HTTP监听器不能配置SSL策略。
补充上下文
相关配置片段(动态模块)
resource "aws_elastic_beanstalk_configuration_template" "env_template" { ... # Dynamic load balancer listeners dynamic "setting" { for_each = var.listeners content { name = "DefaultProcess" namespace = setting.value["port"] == "80" ? "aws:elbv2:listener:default" : "aws:elbv2:listener:${setting.value["port"]}" value = setting.value["process"] } } dynamic "setting" { for_each = var.listeners content { name = "Protocol" namespace = setting.value["port"] == "80" ? "aws:elbv2:listener:default" : "aws:elbv2:listener:${setting.value["port"]}" value = setting.value["protocol"] } } dynamic "setting" { for_each = var.listeners content { name = "ListenerEnabled" namespace = setting.value["port"] == "80" ? "aws:elbv2:listener:default" : "aws:elbv2:listener:${setting.value["port"]}" value = setting.value["enabled"] } } dynamic "setting" { for_each = [ for listener in var.listeners : listener if listener.protocol == "HTTPS" ] content { name = "SSLCertificateArns" namespace = setting.value["port"] == "80" ? "aws:elbv2:listener:default" : "aws:elbv2:listener:${setting.value["port"]}" value = setting.value["ssl_cert_arn"] } } dynamic "setting" { for_each = [ for listener in var.listeners : listener if listener.protocol == "HTTPS" ] content { name = "SSLPolicy" namespace = setting.value["port"] == "80" ? "aws:elbv2:listener:default" : "aws:elbv2:listener:${setting.value["port"]}" value = setting.value["ssl_policy"] } } ... }
resource "aws_elastic_beanstalk_environment" "env" { count = 2 name = element(var.environment_names, count.index) application = var.application_name tier = "WebServer" wait_for_ready_timeout = "20m" template_name = aws_elastic_beanstalk_configuration_template.env_template.name }
Terraform状态文件中的默认监听器配置
{ "name": "DefaultProcess", "namespace": "aws:elbv2:listener:default", "resource": null, "value": "redirect" }, { "name": "ListenerEnabled", "namespace": "aws:elbv2:listener:default", "resource": null, "value": "true" }, { "name": "Protocol", "namespace": "aws:elbv2:listener:default", "resource": null, "value": "HTTP" }
S3中保存的配置(Terraform生成)
aws:elbv2:listener:default: ListenerEnabled: true SSLPolicy: '' SSLCertificateArns: '' DefaultProcess: redirect Protocol: HTTP
控制台手动配置后保存的文件
:default.aws:elbv2:listener:default: ListenerEnabled: true DefaultProcess: redirect
我无法让Terraform生成和控制台一致的正确配置。
解决方案
原因分析
Terraform的EB配置模板资源会自动填充未显式设置的SSL相关参数为空字符串,而AWS EB API对默认HTTP监听器的处理逻辑是:如果存在SSLPolicy或SSLCertificateArns参数(哪怕是空值),就会尝试验证SSL配置,导致冲突错误。
解决步骤
针对默认监听器单独处理,跳过SSL配置项
修改动态配置块,对默认80端口的HTTP监听器,完全跳过SSL相关的setting块,仅为非默认的HTTPS监听器添加SSL配置:# 仅为非默认的HTTPS监听器添加SSL配置 dynamic "setting" { for_each = [ for listener in var.listeners : listener if listener.protocol == "HTTPS" && listener.port != "80" ] content { name = "SSLCertificateArns" namespace = "aws:elbv2:listener:${setting.value["port"]}" value = setting.value["ssl_cert_arn"] } } dynamic "setting" { for_each = [ for listener in var.listeners : listener if listener.protocol == "HTTPS" && listener.port != "80" ] content { name = "SSLPolicy" namespace = "aws:elbv2:listener:${setting.value["port"]}" value = setting.value["ssl_policy"] } }确保默认监听器的Protocol显式设为HTTP
维持现有显式配置,避免Terraform隐式修改该参数。强制刷新配置模板
执行以下命令重新生成配置模板并部署:terraform destroy -target aws_elastic_beanstalk_configuration_template.env_template terraform apply
验证
部署完成后,从S3下载EB配置文件,应该和控制台手动配置的格式一致,不再包含SSLPolicy和SSLCertificateArns空值项,同时默认监听器可正常转发到"redirect"进程。
内容的提问来源于stack exchange,提问作者Chris.B

