概述
Kibana 是一种流行的开源可视化工具,专为与 Elasticsearch 结合使用而设计。Amazon ES 为每个 Amazon ES 域默认安装 Kibana。目前 ES 内置的 Kibana 不支持 IAM,对于 Kibana 的访问控制主要有两个方面:在 VPC 内访问可以通过安全组进行控制,在 VPC 外访问可以通过结合 Amazon Cognito 的 User Pool 和 Identity Pool 来进行身份验证或者使用基于 IP 的策略。
由于 AWS 中国区目前还不支持 Cognito User Pool,因此需要在 VPC 外进行公开访问只能通过基于 IP 的策略来进行控制。当需要访问 ES Kibana 的员工发生变化或者人数变多时,基于 IP 的策略进行管理控制就显得不那么方便了。因此我们可以用一个 Nginx 服务器作为中间代理,将这台 Nginx 的 IP 加入 Kibana 的访问策略中,客户端通过 Nginx 的反向代理来访问 Kibana,而关于身份验证的部分在 Nginx 上实现。
基于以上分析,关于中国区 Amazon Elaticsearch Kibana 身份验证问题,提出了用 Nginx 作为代理并且在 Nginx 做身份验证的三种解决方案。关于每个方案的具体架构和原理以及适用场景分析具体查看通篇博文。
方案一:使用 Nginx 作为代理,做 HTTP 基本认证,实现简单但是安全系数不高。
方案二:使用 Nginx 作为代理,做 OIDC 认证(这里以 Okta 为例),使用免费版本 Nginx 即可实现 OAuth 和 OIDC 后端认证。
方案三:使用 Nginx plus 作为代理,以 Okta 为 Idp 做 OIDC 认证,使用付费版本 Nginx Plus 实现 OIDC 后端认证。
前提条件
本博文下三个方案的演示都在 AWS 中国宁夏区域完成。在方案开始之前,请准备好以下 AWS 基本环境:
方案一:在 Nginx 上做 HTTP 基本认证
利用 Nginx 的 auth_basic 模块,也就是 HTTP Basic Authentication,是 HTTP 服务器对 WEB 浏览器进行基本身份认证的方法。
原理
当客户端向 HTTP 服务器进行数据请求时,如果客户端未被认证,则 HTTP 服务器将通过基本认证过程对客户端的用户名及密码进行验证,以决定用户是否合法。客户端在接收到 HTTP 服务器的身份验证要求后,会提示用户输入用户名密码,然后将用户名密码以 BASE64 加密,加密后的密文将附加于请求信息。并于每次请求数据时,将密文附加于请求头(Request Header)中。HTTP 服务器在每次收到请求包后,根据协议取得客户端附加的用户信息(BASE64 加密的用户名和密码),解开请求包,对用户名及密码进行验证。
优缺点
优点:提供简单的用户认证功能,其实现和认证过程都简单明了,适合于对安全要求不高的系统
缺点:
实现过程
在 EC2 上安装 Nginx
Html
sudo yum update -y
# 在yum中添加nginx官网yum源
sudo rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
sudo yum install -y nginx
sudo systemctl start nginx
sudo systemctl status nginx
复制代码
使用以下内容直接覆盖 Nginx 的配置文件/etc/nginx/nginx.conf
Html
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# Load modular configuration files from the /etc/nginx/conf.d directory.
include /etc/nginx/conf.d/*.conf;
index index.html index.htm;
}
复制代码
修改文件 /etc/nginx/conf.d/default.conf 为以下内容,主要修改两个参数:其中 “EC2_pulicDNS” 为 EC2 的公有 DNS,可以在 AWS EC2 控制台中查看;“ES_Kibana_url” 为 Elasticsearch Service 中 Kibana 的 url,可以在 Elasticsearch Service 创建的域控制台上查看。
Html
server {
listen 80;
server_name {EC2_publicDNS};
auth_basic "Kibana Auth";
auth_basic_user_file /etc/nginx/.httpd_secret;
rewrite ^/$ http://{EC2_publicDNS}/_plugin/kibana redirect;
location /_plugin/kibana {
# Forward requests to Kibana
proxy_pass {ES_Kibana_url};
# Update cookie domain and path
proxy_cookie_domain {ES_Kibana_url} {EC2_publicDNS};
proxy_cookie_path / /_plugin/kibana/;
proxy_set_header Authorization "";
# Response buffer settings
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
}
}
复制代码
修改完配置文件后使用以下命令重启 Nginx
Html
sudo systemctl restart nginx
复制代码
如下图所示在 AWS 的 Elasticsearch 控制台修改 domain 的访问策略,加上 Nginx 也就是 EC2 的公有 IP
Html
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "es:*",
"Resource": "arn:aws:es:ap-northeast-1:{AWS-账号}:domain/beckydomain/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"EC2_pulicIP": {ec2-public-ip}
]
}
}
}
]
}
复制代码
测试
Html
# 安装httpd
sudo yum install -y httpd-tools
# 用httpd工具生成kibana-admin访问
sudo htpasswd -c /etc/nginx/.httpd_secret kibana-admin
复制代码
直接访问 EC2 的公有 DNS,会跳出 HTTP 基本认证的弹框,使用 httpd-tools 生成 kibana-admin 账号的密码登录后就会自动跳转到 ES Kibana 界面。
方案二:在 Nginx 上做 OIDC 认证(以 Okta 为例)
基础
Nginx auth_request:模块位于 Internet 和 Nginx 将请求传递到的后端服务器之间,并且每当有请求进入时,它首先将请求转发到单独的服务器以检查用户是否已通过身份验证,并使用 HTTP 响应来决定是否允许请求继续到后端。
Vouch:Nginx 的 auth_request 模块没有用户或对任何人进行身份验证的概念,因此在这里我们还需要选择一个身份验证代理,开实际处理登录用户的内容,负责处理 HTTP 请求,并且根据用户是否登录来返回 HTTP 200 或者 401,如果用户未登录,则需要知道如何让他们登录并且设置会话 cookie。Vouch 是用 Go 编写的,可以为 Vouch 配置 OAuth 和 OpenID Connect 后端对用户进行身份验证。
Okta:Okta 是一个符合 OAuth 和 OIDC 的标准身份认证服务,可以进行用户管理,实现 SSO 和 MFA 等,在这里作为一个标准的 OIDC 提供商
架构和原理
方案二的架构和原理如下图所示,在本实例中,kibana.stats.beckyhome.cn 为 Nginx 服务器也就是用户访问 Kibana 的域名, kibana.login.beckyhome.cn 为 Vouch 服务器也就是中间做认证跳转的域名,在这里两个域名都指向 EC2 的公有 IP。本博文使用 Amazon Route53 进行 DNS 管理。您需要将这两个域名替换成自己的域名,并使用 Route53 或者您自己的 DNS 服务将域名指向 EC2 的公有 IP(测试情况下公开访问也需要指定)。
终端用户访问 http://kibana.stats.beckyhome.cn
Nginx 反向代理
收到用户对 kibana.stats.beckyhome.cn 的请求
使用 auth_request 模块配置路径/vouch_validate
/vouch_validate 通过 proxy_pass 向 http://kibana.stats.beckyhome.cn/validate 请求验证
如果/vouch_validate 为 200 OK,成功返回
如果/vouch_validate 为 401 NotAuthorized,302 重定向到 http://kibana.login.beckyhome.cn/login?url=http://kibana.stats.beckyhome.cn
vouch /vouch_validate 验证过程
从 Nginx 的 proxy_pass 收到 kibana.stats.beckyhome.cn 的请求
寻找包含 JWT 的名为“oursitesSSO”的 cookie
cookie 找到,并且 JWT 有效:返回 200 给 Nginx,允许访问(用户无感知)
cookie 没找到,或者 KWT 无效:返回 401 NotAuthorized 给 Nginx
请求转发给 https://kibana.login.beckyhome.cn/login?url=https://kibana.stats.beckyhome.cn
清除名为“oursitesSSO”的 cookie(如果存在)
生成一个随机数并将其存储在会话变量 $STATE 中
将 http://kibana.login.beckyhome.cn 查询字符串中的 url 存储在会话变量 $ requestedURL 中
使用 302 重定向 Okta 的 OIDC 登录表单(包括 $STATE 随机数)回给用户
Okta 验证
用户在 okta 表单输入用户名和密码登录
okat 验证后,将用户重定向回 $requestedURL
请求转发到 ES Kibana
前面 Nginx 的 auth_request 验证通过后,请求重定向到 Elasticsearch Kibana 的 url
优缺点
优点:
缺点:需要安装第三方开源工具 Vouch,且配置过程较为复杂
配置 Nginx
在 EC2 上安装 Nginx 后,检查是否安装了 http_auth_request_module,高版本 nginx(1.5.4+)下默认安装
如果没有 auth_request 模块,需要下载重新编译
Html
# 下载依赖
yum -y install gcc gcc-c++ autoconf automake make zlib zlib-devel openssl openssl-devel pcre pcre-devel libxslt-devel redhat-rpm-config gd-devel perl-devel perl-ExtUtils-Embed geoip-devel gperftools-devel
# 下载源代码
./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie' --with-http_auth_request_module
# 编译安装
make
make install
复制代码
在/etc/nginx/conf.d 目录下新建文件 nginx.conf,用以下配置替换内容。其中,“kibana.stats.beckyhome.cn” 和 “kibana.login.beckyhome.cn” 请换成您自己的域名。“ES_Kibana_url” 为 Elasticsearch Service 中 Kibana 的 url,其他内容保持不变。
Html
server {
listen 80 default_server;
server_name {kibana.stats.beckyhome.cn};
# Any request to this server will first be sent to this URL
auth_request /vouch-validate;
location = /vouch-validate {
# This address is where Vouch will be listening on
proxy_pass http://127.0.0.1:9090/validate;
proxy_pass_request_body off; # no need to send the POST body
proxy_set_header Content-Length "";
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 $scheme;
# these return values are passed to the @error401 call
auth_request_set $auth_resp_jwt $upstream_http_x_vouch_jwt;
auth_request_set $auth_resp_err $upstream_http_x_vouch_err;
auth_request_set $auth_resp_failcount $upstream_http_x_vouch_failcount;
}
error_page 401 = @error401;
# If the user is not logged in, redirect them to Vouch's login URL
location @error401 {
return 302 http://{kibana.login.beckyhome.cn}/login?url=http://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err;
}
rewrite ^/$ http://{kibana.stats.beckyhome.cn}/_plugin/kibana redirect;
location /_plugin/kibana {
# Forward requests to Kibana
proxy_pass {ES_Kibana_url};
# Update cookie domain and path
proxy_cookie_domain {ES_Kibana_url} {kibana.stats.beckyhome.cn};
proxy_cookie_path / /_plugin/kibana/;
proxy_set_header Authorization "";
# Response buffer settings
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
}
}
复制代码
在/etc/nginx/conf.d 目录下新建文件 vouch.conf,用以下配置替换其内容。同样将“kibana.login.beckyhome.cn” 换成您自己的域名。
Html
server {
listen 80;
server_name {kibana.login.beckyhome.cn};
# Proxy to your Vouch instance
location / {
proxy_set_header Host {kibana.login.beckyhome.cn};
proxy_pass http://127.0.0.1:9090;
}
}
复制代码
修改完配置文件后使用以下命令重启 Nginx
Html
sudo systemctl restart nginx
复制代码
配置 Okta
注册后,在Develop Okta上创建 Application 选择 WEB
填写 Base URI 和 Login redirect URIs,同样将“kibana.login.beckyhome.cn” 换成您自己的域名。其他默认不变。
下载 Client ID 和 Client secret
配置 Vouch
Html
# 安装go和git
cd ~
# vouch的所有操作都在root下进行
sudo -s
yum install golang
yum install git
git clone https://github.com/vouch/vouch-proxy.git
复制代码
在 vouch_proxy/config 文件夹下新建 config.yml 文件,用以下内容替换。其中 “client_id” 和 “client_secret” 为上一步下载的 ClientID 和 Client secret,“yourOktaDomain”换成您个人账户的 Okta 域名(在 Okta console 中查看, 如”https://dev-123456.okta.com/,可以参考Okta帮助文档) ,将 “kibana.login.beckyhome.cn” 换成您自己的域名,“beckyhome.cn” 换成根域名。
Html
# vouch config
vouch:
logLevel: info
testing: false
listen: 0.0.0.0
port: 9090
allowAllUsers: true
jwt:
secret: your_random_string
issuer: Vouch
maxAge: 240
compress: true
cookie:
name: VouchCookie
domain: {beckyhome.cn}
secure: false
httpOnly: true
maxAge: 0
session:
name: VouchSession
key: you_random_key
headers:
jwt: X-Vouch-Token
querystring: access_token
redirect: X-Vouch-Requested-URI
# OAuth Provider:OpenID Connect Okta
oauth:
provider: oidc
client_id: {client_id}
client_secret: {client_secret}
auth_url: https://{yourOktaDomain}/oauth2/default/v1/authorize
token_url: https://{yourOktaDomain}/oauth2/default/v1/token
user_info_url: https://{yourOktaDomain}/oauth2/default/v1/userinfo
scopes:
- openid
- email
# Set the callback URL to the domain that Vouch is running on
callback_url: http://{kibana.login.beckyhome.cn}/auth
复制代码
回到vouch-proxy文件夹下,编译和运行vouch(root下)。
复制代码
Html
./do.sh goget
./do.sh build
./vouch-proxy
复制代码
注意:在中国区 EC2 上执行./do.sh goget 会报以下错误
Html
https fetch failed: Get https://golang.org/x/text/... timeout
https fetch failed: Get https://golang.org/x/sys/.. timeout
https fetch failed: Get https://golang.org/x/oauth2/.. timeout
https fetch failed: Get https://golang.org/x/net/.. timeout
https fetch failed: Get https://cloud.google.com/go/compute/metadata/.. timeout
复制代码
解决办法:使用国内 github 的镜像库代替国外镜像库,手动下载完成后不需要再执行 goget 直接进入 build 阶段
Html
# 查看go安装的位置GOPATH
go env
export GOPATH=/root/go
echo $GOPATH
# 手动添加文件夹golang.org
mkdir -p $GOPATH/src/golang.org/x
cd $GOPATH/src/golang.org/x
git clone https://github.com/golang/text.git
git clone https://github.com/golang/sys.git
git clone https://github.com/golang/oauth2.git
git clone https://github.com/golang/net.git
# 手动添加文件夹cloud.google.com
mkdir -p $GOPATH/src/cloud.google.com/go
cd $GOPATH/src/cloud.google.com/go
git clone https://github.com/googleapis/google-cloud-go.git
# 移动文件夹compute到指定位置
mv $GOPATH/src/cloud.google.com/go/google-cloud-go/compute $GOPATH/src/cloud.google.com/go/compute
复制代码
测试
在 Okta 中创建一个用户,并 attach 到 kibana 的 application
访问域名 kibana.stats.beckyhome.cn 跳转到 okta 的登录表单
登录之后跳转到 Kibana 界面
方案三:在 Nginx plus 上以 Okta 为 Idp 做 OIDC 认证
方案介绍
方案三的原理与方案二类似,只不过不需要安装第三方身份验证代理,Nginx plus 上的 nginx-plus-module-njs 模块已经官方支持 OIDC 后端。
优缺点
优点:只需安装 Nginx plus 的官方模块即可,配并且配置过程简单
缺点:
Nginx plus 需付费
此方案只适用于 OIDC 认证
配置过程
方案三由 Nginx Plus 官方支持,关于 Okta 以及更详细的配置可以直接参考 Nginx Plus 官方文档:https://docs.nginx.com/nginx/deployment-guides/single-sign-on/okta/
Html
# 安装nginx-plus-module-njs模块
sudo yum install nginx-plus-module-njs
# 创建一个nginx-openid-connect GitHub存储库的克隆
git clone https://github.com/nginxinc/nginx-openid-connect
# 复制文件到nginx的配置中
cp frontend.conf /etc/nginx/conf.d/frontednss.conf
cp openid_connect.js /etc/nginx/conf.d/openid_connect.js
cp openid_connect.server_conf /etc/nginx/conf.d/openid_connect.server_conf
# 从Okta配置获取授权端点,令牌端点和JSON Web密钥(JWK)文件的URL
$ curl https:// <用户名> -admin.okta.com/.well-known/openid-configuration | python -m json.tool
复制代码
修改文件/etx/nginx/conf.d/frontend.conf 的以下值
Html
set $oidc_authz_endpoint – authorization_endpoint
set $oidc_token_endpoint – token_endpoint
set $oidc_client – {client_id}
set $oidc_client_secret – {client_secret}
set $oidc_token_type – id_token
复制代码
方案总结
以上提出的三个方案的优缺点总结如下所示。
col 1 | col 2 | col 3 | col 4 |
---|
A | 方案一 | 方案二 | 方案三 |
方案说明 | Nginx作为代理,做HTTP基本认证 | Nginx作为代理,做OIDC认证(这里以Okta为例) | |
| Nginx plus作为代理,以Okta为Idp做OIDC认证
复制代码
优点 | 原理和配置过程都比较简单 | · 使用免费社区版 Nginx 即可;
· 支持各个标准的 OAuth 和 OIDC 后端认证(包括 Google,Facebook,Github,Amazon Cognito,Okta 等);
· 可以灵活得进行用户和权限的控制 | 只需安装 Nginx plus 的官方模块即可,配并且配置过程简单
缺点 | 安全程度低,不能灵活或者集中进行用户的管理和授权 | 需要安装第三方开源工具 Vouch,且配置过程较为复杂
| Nginx plus需付费,并且此方案只适用于OIDC 认证
复制代码
适用场景 | 对安全要求不高的小型客户 | 对安全要求比较高,有多个 OAuth 和 OIDC 认证后端,又不想付费购买 Nginx Plus 的客户 | 对安全要求高,内部只有 OIDC 后端,不想安装第三方工具并且有经济实力的客户
本文转载自 AWS 技术博客。
原文链接:https://amazonaws-china.com/cn/blogs/china/a-solution-to-authenticate-amazon-elasticsearch-kibana-in-aws-china/
评论