无法通过 AWS 负载均衡器 HTTPS 访问气流 Web 服务器,因为气流将我重定向到 HTTP
Cannot access airflow web server via AWS load balancer HTTPS because airflow redirects me to HTTP
我在 EC2 上配置了一个 airflow web 服务器,它在端口 8080 上侦听。
我在 EC2 前面有一个 AWS ALB(应用程序负载均衡器),监听 https 80(面向互联网),实例目标端口面向 http 8080。
我无法从浏览器浏览 https://< airflow link >,因为 airflow Web 服务器将我重定向到 http : //< airflow link >/admin,ALB 不会这样做收听
如果我从浏览器浏览 https://< airflow link > /admin/airflow/login?next=%2Fadmin%2F,那么我会看到登录页面,因为这个 link 没有重定向我。
我的问题是如何更改 airflow 以便在浏览 https://< airflow link > 时,airflow 网络服务器会将我重定向到 https:...,而不是 http://... ..
以便 AWS ALB 可以处理请求。
我尝试根据以下答案将 airflow.cfg 的 base_url 从 http://localhost:8080 to https://localhost:8080 更改,但我没有发现我的更改有任何区别....
无论如何,如何从 ALB 访问 https://< airflow link >?
我认为您的一切工作正常。您看到的重定向是预期的,因为网络服务器是 set to redirect 从 /
到 /admin
。如果您使用的是 curl,则可以传递标志 -L
/ --location
以跟随重定向,它应该会将您带到 DAG 列表。
另一个很好的测试端点是 https://<airflow domain name>/health
(没有尾部斜线,否则你会得到 404!)。它应该 return "The server is healthy!".
请确保您在气流配置的网络服务器部分下的 base_url
中有 https://
。
最后我自己找到了解决办法。
我在 ALB 和 airflow 网络服务器之间引入了一个 nginx 反向代理:即。
https 请求 ->ALB:443 ->nginx 代理:80 ->web server:8080。我通过添加 http header "X-Forwarded-Proto https" 让 nginx 代理告诉 airflow web 服务器原始请求是 https 而不是 http。
nginx 服务器与网络服务器 co-located。我将它的配置设置为 /etc/nginx/sites-enabled/vhost1.conf(见下文)。此外,我删除了 /etc/nginx/sites-enabled/default 配置文件。
server {
listen 80;
server_name <domain>;
index index.html index.htm;
location / {
proxy_pass_header Authorization;
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_http_version 1.1;
proxy_redirect off;
proxy_set_header Connection "";
proxy_buffering off;
client_max_body_size 0;
proxy_read_timeout 36000s;
}
}
用户 user389955 自己的解决方案可能是最好的方法,但对于任何寻求快速修复(或想更好地了解正在发生的事情)的人来说,这似乎是罪魁祸首。
在以下文件中(python 发行版可能不同):
/usr/local/lib/python3.5/dist-packages/gunicorn/config.py
以下部分防止从除本地
以外的任何地方转发 headers
class ForwardedAllowIPS(Setting):
name = "forwarded_allow_ips"
section = "Server Mechanics"
cli = ["--forwarded-allow-ips"]
meta = "STRING"
validator = validate_string_to_list
default = os.environ.get("FORWARDED_ALLOW_IPS", "127.0.0.1")
desc = """\
Front-end's IPs from which allowed to handle set secure headers.
(comma separate).
Set to ``*`` to disable checking of Front-end IPs (useful for setups
where you don't know in advance the IP address of Front-end, but
you still trust the environment).
By default, the value of the ``FORWARDED_ALLOW_IPS`` environment
variable. If it is not defined, the default is ``"127.0.0.1"``.
"""
从 127.0.0.1
更改为特定 IP 或 *
(如果 IP 未知)即可解决问题。
此时,我还没有找到在气流配置本身中设置此参数的方法。如果我找到办法,会更新我的答案。
因为他们使用的是 Gunicorn - 您可以将 forwarded_allow_ips 值配置为环境变量,而不必使用像 Nginx 这样的中间代理。
在我的例子中,我只是设置了 FORWARDED_ALLOW_IPS = *
,它工作得很好。
在 ECS 中,如果您对所有 Airflow 任务(网络服务器、调度程序、工作程序等)使用一个 docker 图像,则可以在网络服务器任务配置中进行设置。
深入研究 the gunicorn documentation:似乎可以通过 GUNICORN_CMD_ARGS
环境变量传递任何命令行参数(当调用 gunicorn 命令时)。
所以我正在尝试设置 GUNICORN_CMD_ARGS=--forwarded-allow-ips=*
因为所有流量都将从 AWS ALB 到达我的实例...我想通配符可以替换为 ALB 的实际 IP 作为实例看到了,但这将是下一步...
因为我在 ECS 上 运行,所以我将其传递为:
- Name: GUNICORN_CMD_ARGS
Value: --forwarded-allow-ips=*
在我的 task's container definition 的 Environment
中。
PS:从文档中,这种可能性是从 gunicorn 19.7 开始添加的;相比之下,Airflow 1.10.9 似乎在 gunicorn 19.10 上,非常适合与任何(或多或少)最新版本的 Airflow 一起使用!
我在使用 official apache airflow helm chart(版本 1.0.0)时也遇到了这个问题。
问题
最初我配置了 LoadBalancer
类型的网络服务器服务。
webserver:
service:
type: LoadBalancer
annotations:
service.beta.kubernetes.io/aws-load-balancer-internal: "true"
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-west-2:1234512341234:certificate/231rc-r12c3h-1rch3-1rch3-rc1h3r-1r3ch
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp
这导致创建了一个经典的弹性负载平衡器。
这主要是有效的,但是当我点击气流标志(链接到 https://my-domain.com
)时,我会被重定向到 http://my-domain.com/home
,但失败了,因为负载平衡器被配置为仅使用 HTTPS .
解决方案
我通过在我的 EKS 集群上安装 AWS Load Balancer Controller 然后配置入口解决了这个问题。
图表配置的入口相关部分如下所示:
ingress:
enabled: true
web:
host: my-airflow-address.com
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/subnets: subnet-01234,subnet-01235,subnet-01236
alb.ingress.kubernetes.io/scheme: internal # if in private subnets
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
webserver:
service:
type: NodePort
备注
可能可以将网络服务器配置为使用 ALB 而不是经典 ELB 并将其配置为处理 HTTP 路由,但我还没有测试过。
我们在我的团队中解决了这个问题,方法是向我们的 ALB 添加一个 HTTP 侦听器,将所有 HTTP 流量重定向到 HTTPS(因此我们有一个 HTTP 侦听器和一个 HTTPS 侦听器)。我们的 Airflow 网络服务器任务仍然在端口 80 上侦听 HTTP 流量,但此 HTTP 流量仅在我们的 VPC 中,因此我们不关心。从浏览器到负载平衡器的连接始终是 HTTPS 或重新路由到 HTTPS 的 HTTP,这才是最重要的。
这是新监听器的 Terraform 代码:
resource "aws_lb_listener" "alb_http" {
load_balancer_arn = aws_lb.lb.arn
port = 80
protocol = "HTTP"
default_action {
type = "redirect"
redirect {
port = "443"
protocol = "HTTPS"
status_code = "HTTP_301"
}
}
}
或者,如果您是 AWS 控制台,这里是您为侦听器设置默认操作的方式:
Console
我在 EC2 上配置了一个 airflow web 服务器,它在端口 8080 上侦听。
我在 EC2 前面有一个 AWS ALB(应用程序负载均衡器),监听 https 80(面向互联网),实例目标端口面向 http 8080。
我无法从浏览器浏览 https://< airflow link >,因为 airflow Web 服务器将我重定向到 http : //< airflow link >/admin,ALB 不会这样做收听
如果我从浏览器浏览 https://< airflow link > /admin/airflow/login?next=%2Fadmin%2F,那么我会看到登录页面,因为这个 link 没有重定向我。
我的问题是如何更改 airflow 以便在浏览 https://< airflow link > 时,airflow 网络服务器会将我重定向到 https:...,而不是 http://... .. 以便 AWS ALB 可以处理请求。
我尝试根据以下答案将 airflow.cfg 的 base_url 从 http://localhost:8080 to https://localhost:8080 更改,但我没有发现我的更改有任何区别....
无论如何,如何从 ALB 访问 https://< airflow link >?
我认为您的一切工作正常。您看到的重定向是预期的,因为网络服务器是 set to redirect 从 /
到 /admin
。如果您使用的是 curl,则可以传递标志 -L
/ --location
以跟随重定向,它应该会将您带到 DAG 列表。
另一个很好的测试端点是 https://<airflow domain name>/health
(没有尾部斜线,否则你会得到 404!)。它应该 return "The server is healthy!".
请确保您在气流配置的网络服务器部分下的 base_url
中有 https://
。
最后我自己找到了解决办法。
我在 ALB 和 airflow 网络服务器之间引入了一个 nginx 反向代理:即。 https 请求 ->ALB:443 ->nginx 代理:80 ->web server:8080。我通过添加 http header "X-Forwarded-Proto https" 让 nginx 代理告诉 airflow web 服务器原始请求是 https 而不是 http。
nginx 服务器与网络服务器 co-located。我将它的配置设置为 /etc/nginx/sites-enabled/vhost1.conf(见下文)。此外,我删除了 /etc/nginx/sites-enabled/default 配置文件。
server {
listen 80;
server_name <domain>;
index index.html index.htm;
location / {
proxy_pass_header Authorization;
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_http_version 1.1;
proxy_redirect off;
proxy_set_header Connection "";
proxy_buffering off;
client_max_body_size 0;
proxy_read_timeout 36000s;
}
}
用户 user389955 自己的解决方案可能是最好的方法,但对于任何寻求快速修复(或想更好地了解正在发生的事情)的人来说,这似乎是罪魁祸首。
在以下文件中(python 发行版可能不同):
/usr/local/lib/python3.5/dist-packages/gunicorn/config.py
以下部分防止从除本地
以外的任何地方转发 headersclass ForwardedAllowIPS(Setting):
name = "forwarded_allow_ips"
section = "Server Mechanics"
cli = ["--forwarded-allow-ips"]
meta = "STRING"
validator = validate_string_to_list
default = os.environ.get("FORWARDED_ALLOW_IPS", "127.0.0.1")
desc = """\
Front-end's IPs from which allowed to handle set secure headers.
(comma separate).
Set to ``*`` to disable checking of Front-end IPs (useful for setups
where you don't know in advance the IP address of Front-end, but
you still trust the environment).
By default, the value of the ``FORWARDED_ALLOW_IPS`` environment
variable. If it is not defined, the default is ``"127.0.0.1"``.
"""
从 127.0.0.1
更改为特定 IP 或 *
(如果 IP 未知)即可解决问题。
此时,我还没有找到在气流配置本身中设置此参数的方法。如果我找到办法,会更新我的答案。
因为他们使用的是 Gunicorn - 您可以将 forwarded_allow_ips 值配置为环境变量,而不必使用像 Nginx 这样的中间代理。
在我的例子中,我只是设置了 FORWARDED_ALLOW_IPS = *
,它工作得很好。
在 ECS 中,如果您对所有 Airflow 任务(网络服务器、调度程序、工作程序等)使用一个 docker 图像,则可以在网络服务器任务配置中进行设置。
深入研究 the gunicorn documentation:似乎可以通过 GUNICORN_CMD_ARGS
环境变量传递任何命令行参数(当调用 gunicorn 命令时)。
所以我正在尝试设置 GUNICORN_CMD_ARGS=--forwarded-allow-ips=*
因为所有流量都将从 AWS ALB 到达我的实例...我想通配符可以替换为 ALB 的实际 IP 作为实例看到了,但这将是下一步...
因为我在 ECS 上 运行,所以我将其传递为:
- Name: GUNICORN_CMD_ARGS
Value: --forwarded-allow-ips=*
在我的 task's container definition 的 Environment
中。
PS:从文档中,这种可能性是从 gunicorn 19.7 开始添加的;相比之下,Airflow 1.10.9 似乎在 gunicorn 19.10 上,非常适合与任何(或多或少)最新版本的 Airflow 一起使用!
我在使用 official apache airflow helm chart(版本 1.0.0)时也遇到了这个问题。
问题
最初我配置了 LoadBalancer
类型的网络服务器服务。
webserver:
service:
type: LoadBalancer
annotations:
service.beta.kubernetes.io/aws-load-balancer-internal: "true"
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-west-2:1234512341234:certificate/231rc-r12c3h-1rch3-1rch3-rc1h3r-1r3ch
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp
这导致创建了一个经典的弹性负载平衡器。
这主要是有效的,但是当我点击气流标志(链接到 https://my-domain.com
)时,我会被重定向到 http://my-domain.com/home
,但失败了,因为负载平衡器被配置为仅使用 HTTPS .
解决方案
我通过在我的 EKS 集群上安装 AWS Load Balancer Controller 然后配置入口解决了这个问题。
图表配置的入口相关部分如下所示:
ingress:
enabled: true
web:
host: my-airflow-address.com
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/subnets: subnet-01234,subnet-01235,subnet-01236
alb.ingress.kubernetes.io/scheme: internal # if in private subnets
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
webserver:
service:
type: NodePort
备注
可能可以将网络服务器配置为使用 ALB 而不是经典 ELB 并将其配置为处理 HTTP 路由,但我还没有测试过。
我们在我的团队中解决了这个问题,方法是向我们的 ALB 添加一个 HTTP 侦听器,将所有 HTTP 流量重定向到 HTTPS(因此我们有一个 HTTP 侦听器和一个 HTTPS 侦听器)。我们的 Airflow 网络服务器任务仍然在端口 80 上侦听 HTTP 流量,但此 HTTP 流量仅在我们的 VPC 中,因此我们不关心。从浏览器到负载平衡器的连接始终是 HTTPS 或重新路由到 HTTPS 的 HTTP,这才是最重要的。
这是新监听器的 Terraform 代码:
resource "aws_lb_listener" "alb_http" {
load_balancer_arn = aws_lb.lb.arn
port = 80
protocol = "HTTP"
default_action {
type = "redirect"
redirect {
port = "443"
protocol = "HTTPS"
status_code = "HTTP_301"
}
}
}
或者,如果您是 AWS 控制台,这里是您为侦听器设置默认操作的方式:
Console