feat: 引入 vmauth 鉴权与严格多租户

- 对外端口统一为 18428(vmauth 入口),VM 不再直接暴露宿主机端口
- 边缘 vmagent 与中央 Prometheus remote_write 增加 basic auth
- 支持 tenants.csv 驱动的 per-tenant 写入/查询隔离,并提供管理员跨租户只读查询
- 更新 Grafana provisioning 与部署/文档

Made-with: Cursor
This commit is contained in:
root
2026-04-22 11:41:13 +00:00
parent ab1515dffb
commit c4825c2d27
21 changed files with 278 additions and 37 deletions

View File

@@ -30,7 +30,7 @@ fi
PROMETHEUS_PORT=${PROMETHEUS_PORT:-9091}
GRAFANA_PORT=${GRAFANA_PORT:-3000}
ALERTMANAGER_PORT=${ALERTMANAGER_PORT:-9093}
VICTORIAMETRICS_PORT=${VICTORIAMETRICS_PORT:-8428}
VICTORIAMETRICS_PORT=${VICTORIAMETRICS_PORT:-18428}
PROMETHEUS_DATA_DIR=${PROMETHEUS_DATA_DIR:-./data/prometheus-data}
GRAFANA_DATA_DIR=${GRAFANA_DATA_DIR:-./data/grafana-data}
VICTORIAMETRICS_DATA_DIR=${VICTORIAMETRICS_DATA_DIR:-./data/victoria-metrics-data}
@@ -46,6 +46,12 @@ PROMETHEUS_REMOTE_WRITE_MAX_SHARDS=${PROMETHEUS_REMOTE_WRITE_MAX_SHARDS:-10}
GRAFANA_DEFAULT_LANGUAGE=${GRAFANA_DEFAULT_LANGUAGE:-zh-Hans}
GRAFANA_DEFAULT_THEME=${GRAFANA_DEFAULT_THEME:-light}
TRAEFIK_PROVIDER=${TRAEFIK_PROVIDER:-external}
VMAUTH_WRITE_USER=${VMAUTH_WRITE_USER:-vm_write}
VMAUTH_WRITE_PASSWORD=${VMAUTH_WRITE_PASSWORD:-change-me-strong-write}
VMAUTH_READ_USER=${VMAUTH_READ_USER:-vm_read}
VMAUTH_READ_PASSWORD=${VMAUTH_READ_PASSWORD:-change-me-strong-read}
VMAUTH_ADMIN_USER=${VMAUTH_ADMIN_USER:-vm_admin}
VMAUTH_ADMIN_PASSWORD=${VMAUTH_ADMIN_PASSWORD:-change-me-strong-admin}
# 根据 TRAEFIK_ENABLED 与 TRAEFIK_PROVIDER 设置网络
if [ "${TRAEFIK_ENABLED:-false}" = "true" ]; then
@@ -194,6 +200,147 @@ elif [ ! -f "config/prometheus/prometheus.yml" ]; then
exit 1
fi
generate_vmauth_and_grafana_datasources() {
mkdir -p config/vmauth config/grafana/provisioning/datasources
local tenants_file="config/vmauth/tenants.csv"
local vmauth_out="config/vmauth/vmauth.yml"
local grafana_out="config/grafana/provisioning/datasources/victoriametrics.yml"
echo "📝 生成 vmauth 配置与 Grafana 数据源..."
# vmauth header
cat > "$vmauth_out" <<'EOF'
unauthorized_user:
url_map: []
users:
EOF
# grafana header
cat > "$grafana_out" <<'EOF'
apiVersion: 1
datasources:
EOF
if [ -f "$tenants_file" ]; then
# CSV: tenant_id,edge_node_id,write_user,write_password,read_user,read_password
# Skip header line
tail -n +2 "$tenants_file" | while IFS=',' read -r tenant_id edge_node_id wuser wpass ruser rpass; do
# Skip empty lines
[ -z "$tenant_id" ] && continue
# vmauth write user (route to per-tenant insert)
cat >> "$vmauth_out" <<EOF
- username: "$wuser"
password: "$wpass"
url_prefix: "http://victoria-metrics:8428/insert/${tenant_id}/prometheus"
EOF
# vmauth read user (route to per-tenant select; allow only query-ish paths)
cat >> "$vmauth_out" <<EOF
- username: "$ruser"
password: "$rpass"
url_map:
- src_paths:
- "/api/v1/query"
- "/api/v1/query_range"
- "/api/v1/series"
- "/api/v1/labels"
- "/api/v1/label/.+/values"
- "/api/v1/export"
- "/federate"
url_prefix: "http://victoria-metrics:8428/select/${tenant_id}/prometheus"
EOF
# grafana datasource per tenant
# name includes tenant_id + edge_node_id for readability
cat >> "$grafana_out" <<EOF
- name: "VictoriaMetrics (tenant ${tenant_id}${edge_node_id:+ - ${edge_node_id}})"
type: prometheus
access: proxy
url: http://vmauth:8427
isDefault: false
editable: true
basicAuth: true
basicAuthUser: "${ruser}"
jsonData:
httpMethod: POST
queryTimeout: 60s
timeInterval: 15s
secureJsonData:
basicAuthPassword: "${rpass}"
EOF
done
echo "✅ 已根据 tenants.csv 生成 vmauth.yml 与 Grafana 多数据源"
else
# Fallback: single-tenant mode using .env variables
cat >> "$vmauth_out" <<EOF
- username: "${VMAUTH_WRITE_USER}"
password: "${VMAUTH_WRITE_PASSWORD}"
url_prefix: "http://victoria-metrics:8428"
- username: "${VMAUTH_READ_USER}"
password: "${VMAUTH_READ_PASSWORD}"
url_map:
- src_paths:
- "/api/v1/query"
- "/api/v1/query_range"
- "/api/v1/series"
- "/api/v1/labels"
- "/api/v1/label/.+/values"
- "/api/v1/export"
- "/federate"
url_prefix: "http://victoria-metrics:8428"
EOF
cat >> "$grafana_out" <<EOF
- name: VictoriaMetrics
type: prometheus
access: proxy
url: http://vmauth:8427
isDefault: false
editable: true
basicAuth: true
basicAuthUser: "${VMAUTH_READ_USER}"
jsonData:
httpMethod: POST
queryTimeout: 60s
timeInterval: 15s
secureJsonData:
basicAuthPassword: "${VMAUTH_READ_PASSWORD}"
EOF
echo "✅ 未找到 tenants.csv已使用单租户 .env 变量生成 vmauth.yml 与 Grafana 数据源"
fi
# Append admin read-only user (can query any tenant via /select/<tenant>/prometheus/...)
cat >> "$vmauth_out" <<EOF
- username: "${VMAUTH_ADMIN_USER}"
password: "${VMAUTH_ADMIN_PASSWORD}"
url_map:
- src_paths:
- "^/select/[0-9]+/prometheus/api/v1/query$"
- "^/select/[0-9]+/prometheus/api/v1/query_range$"
- "^/select/[0-9]+/prometheus/api/v1/series$"
- "^/select/[0-9]+/prometheus/api/v1/labels$"
- "^/select/[0-9]+/prometheus/api/v1/label/.+/values$"
- "^/select/[0-9]+/prometheus/api/v1/export$"
- "^/select/[0-9]+/prometheus/federate$"
url_prefix: "http://victoria-metrics:8428"
EOF
echo "✅ 已追加管理员只读账号(可跨租户查询)"
}
generate_vmauth_and_grafana_datasources
# 检查配置文件
if [ ! -f "config/prometheus/alert_rules.yml" ]; then
echo "❌ 配置文件 config/prometheus/alert_rules.yml 不存在"
@@ -267,6 +414,7 @@ mkdir -p "${VICTORIAMETRICS_DATA_DIR}"
mkdir -p config/grafana/dashboards
mkdir -p config/grafana/provisioning/datasources
mkdir -p config/grafana/provisioning/dashboards
mkdir -p config/vmauth
# 设置目录权限
# Prometheus 需要写权限