搭建 MinIO Gateway 的一点点问题

前言

MinIO Gateway 是一款可以代理 S3、Azure、Nas、HDFS 等服务的软件。可以让用户以兼容 S3 的方式来访问所代理的服务。

具体介绍见:https://docs.min.io/docs/minio-gateway-for-s3.html

使用场景

一、一套代码支持不同对象存储产品。

当前市面常见的对象存储产品有:

  • 阿里云 OSS
  • 腾讯云 COS
  • 华为云 OBS
  • Amazon S3
  • 开源 MinIO

如果你的服务需要使用对象存储,但不同的场景下使用的对象存储服务并不一致,为了避免增加代码开发中适配多种产品的复杂性,

可以使用 MinIO Gateway 做一层代理,代码中仅需支持 MinIO 的访问方式即可。

二、避免大量开通云服务子帐号。

在公司内部,当我们使用云服务商的对象存储产品时,是必须开通云产品的子帐号才能访问的。而子帐号的开通和管理其实并不是

很方便,并且还没办法接入比如 LDAP 等帐号管理系统。此时也可以将对象存储服务用 MinIO Gateway 做一层代理,然后通过 Gateway

来管理对象存储服务的帐号,支持各种帐号管理方式。比如 Keycloak、 LDAP、内部用户等。

具体参见:https://docs.min.io/docs/minio-sts-quickstart-guide

MinIO Gateway 搭建

基本搭建步骤参考官方文档:https://docs.min.io/docs/minio-gateway-for-s3.html

可以使用 docker 或者二进制文件等方式启动 Gateway 服务。

下面说点不一样的

MinIO 编译

编译很简单,MinIO 使用 Go 语言开发,所以需要安装 Go,参见:https://go.dev/doc/install

然后源码中已经有写好的 Makefile,直接执行 make 即可。

适配腾讯云 COS

MinIO Gateway 在启动时会随机生成一个 Bucket 名称,然后利用检查 Bucket 是否存在的 API 确认 S3 服务是否可用,期待的返回状态码是 404,

但腾讯云 COS 强制每个 Bucket 的名字后缀为一串数字 ID,如果不符合格式,则响应 400,导致 MinIO Gateway 探测失败。

日志如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
"""
---------START-HTTP---------
GET /probe-bucket-sign-99lrqve1qm4x/?location= HTTP/1.1
Host: cos.ap-beijing.myqcloud.com
User-Agent: MinIO (darwin; amd64) minio-go/v7.0.20
Authorization: AWS4-HMAC-SHA256 Credential=AKID2uWrwlJabKnzwd3CCwPbWBZhZBWZLr64/20220118/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=**REDACTED**
X-Amz-Content-Sha256: UNSIGNED-PAYLOAD
X-Amz-Date: 20220118T155622Z
Accept-Encoding: gzip

HTTP/1.1 400 Bad Request
Content-Length: 437
Connection: keep-alive
Content-Type: application/xml
Date: Tue, 18 Jan 2022 15:56:25 GMT
Server: tencent-cos

<?xml version='1.0' encoding='utf-8' ?>
<Error>
<Code>InvalidURI</Code>
<Message>Could not parse the specified URI.</Message>
<Resource>cos.ap-beijing.myqcloud.com/probe-bucket-sign-99lrqve1qm4x</Resource>
</Error>

---------END-HTTP---------
"""

在 MinIO 官方以及腾讯云官方都不做修改的情况下,只能通过修改源码重新编译来解决问题。

代码修改位置如下:

https://github.com/minio/minio/cmd/gateway/s3/gateway-s3.go

将其中的 randString 函数返回值修改为数字后缀,比如下图:

img

然后编译即可。

使用独立帐号体系

默认情况下,MinIO 自带一套帐号管理体系,不需要任何配置,但缺点是一旦服务重启则帐号信息丢失。

为了持久化存储帐号数据,需要配合 Etcd 服务。

Etcd部署参见:

https://github.com/etcd-io/etcd/releases

MinIO Gateway 启动方式如下:

1
2
3
4
5
6
7
#!/bin/sh
export MINIO_ROOT_USER="Access Key"
export MINIO_ROOT_PASSWORD="Access Secret"
export _MINIO_SERVER_DEBUG=off # 是否开启DEBUG 仅为了查看日志 on|off
export MINIO_ETCD_ENDPOINTS=http://localhost:2379 # 使用 ETCD 持久化存储内部用户
export MINIO_ETCD_PATH_PREFIX=minio/ # ETCD 中存储的数据的前缀
./minio gateway s3 https://cos.ap-beijing.myqcloud.com --console-address 0.0.0.0:9100

不过这种方式有个缺点,新创建的 MinIO Gateway 账密是明文存储在 Etcd 中的。。。

解决办法如下:

  1. 控制 Etcd 的访问权限,避免被其他人访问。

  2. 使用 MinIO 自己的加密方式,参考:https://docs.min.io/docs/minio-kms-quickstart-guide.html。但加密这个功能,加密的地方有点多,而且有点小BUG,比如展示出来的S3文件列表不全。。。所以我放弃了。

集成 LDAP

官方文档:https://github.com/minio/minio/blob/master/docs/sts/ldap.md

启动方式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/sh
export MINIO_ROOT_USER="Access Key"
export MINIO_ROOT_PASSWORD="Access Secret"
export _MINIO_SERVER_DEBUG=off # 是否开启DEBUG 仅为了查看日志 on|off
export MINIO_IDENTITY_LDAP_SERVER_ADDR="LDAP服务器:LDAP服务端口"
export MINIO_IDENTITY_LDAP_LOOKUP_BIND_DN="{LDAP 帐号}" # 例如 cn=readonly,dc=test,dc=com 仅用只读帐号即可
export MINIO_IDENTITY_LDAP_LOOKUP_BIND_PASSWORD="{LDAP 密码}"
export MINIO_IDENTITY_LDAP_USER_DN_SEARCH_BASE_DN='ou=People,dc=test,dc=com' # 搜索域
export MINIO_IDENTITY_LDAP_USER_DN_SEARCH_FILTER='(uid=%s)' # 用来过滤登录的帐号 %s会被填充用户名
export MINIO_IDENTITY_LDAP_TLS_SKIP_VERIFY=on
export MINIO_IDENTITY_LDAP_SERVER_INSECURE=on
export MINIO_IDENTITY_LDAP_SERVER_STARTTLS=off
./minio gateway s3 https://cos.ap-beijing.myqcloud.com --console-address 0.0.0.0:9100

集成 LDAP 的好处就是不用单独开通帐号即可使用,但比较麻烦的是,只能通过命令行 mc 来对用户进行授权。而且当需要给公司外部人员开通帐号时,也必须得开通 LDAP 帐号,可能面临一定的风险。

集成 Audit Log 功能(审计日志)

默认情况下,当仅仅使用 MinIO 的 Gateway 功能时,Admin API 以及很多特性比如 Audit log 都是没有开放的。

这个时候就又到了改代码重新编译的时候。

首先是启用 Admin API,修改代码位置如下:

https://github.com/minio/minio/cmd/gateway-main.go

将下图所示地方改为 true:

然后重新编译即可。

下面是开启 Audit log。参见:https://github.com/minio/operator/tree/master/logsearchapi

按照文档步骤,启动 postgres 数据库,然后启动 logsearchapi 服务,这些都没有问题。

postgres启动:

1
2
3
4
5
6
7
docker run -d \
--name postgres \
-p 5432:5432 \
-e POSTGRES_PASSWORD="xxx" \
-e PGDATA=/var/lib/postgresql/data/pgdata \
-v /data/postgres:/var/lib/postgresql/data \
postgres:14.1 -c "log_statement=all"

logsearchapi启动(注意 logsearchapi 命令也是需要下载源码然后编译的)

1
2
3
4
5
export LOGSEARCH_PG_CONN_STR="postgres://postgres:xxx@localhost/postgres?sslmode=disable"
export LOGSEARCH_AUDIT_AUTH_TOKEN=logsearch_audit
export MINIO_LOG_QUERY_AUTH_TOKEN=logsearch_query
export LOGSEARCH_DISK_CAPACITY_GB=5
./logsearchapi

但当我尝试使用 mc admin 命令设置 aduit_webhook 参数时,却会出现莫名奇妙的错误,一番尝试后放弃,改用其他方式。

将如下代码加入启动脚本即可:

1
2
3
4
5
6
# audit log 功能
export MINIO_AUDIT_WEBHOOK_ENABLE_1="on" # audit log 功能
export MINIO_AUDIT_WEBHOOK_ENDPOINT_1="http://localhost:8080/api/ingest?token=logsearch_audit" # audit log 功能
export MINIO_LOG_QUERY_URL="http://localhost:8080"
export MINIO_LOG_QUERY_AUTH_TOKEN="logsearch_query"
export LOGSEARCH_QUERY_AUTH_TOKEN="logsearch_query"