infisical 基础使用

Infisical 的主要用途

Infisical 是一个开源端到端加密平台,其实就是一个KMS密钥管理系统,它可以集中管理应用中的敏感信息,避免暴露在原始代码中,通过自有的API访问获取

https://infisical.com/docs/self-hosting

helm 搭建

服务端
https://infisical.com/docs/self-hosting/deployment-options/kubernetes-helm

需要先创建 ns:infisical secret:infisical-secrets

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
apiVersion: v1
kind: Namespace
metadata:
name: infisical

---
apiVersion: v1
kind: Secret
metadata:
name: infisical-secrets
namespace: infisical
type: Opaque
stringData:
AUTH_SECRET: CZgwPd65jd0kSUJ7+uxNftvWwmSfsiMtL+v9s6wzUPI=
ENCRYPTION_KEY: 8c0b617685e12744475e20f2a0fe2fd2
SITE_URL: https://infisical.k8s.grafana.eu.org
# 不设置默认内置数据库,也可以用外部数据库
# REDIS_URL: redis://:[email protected]:6379/1
# DB_CONNECTION_URI: postgres://postgres:[email protected]:5432/infisical
SMTP_HOST: smtp.grafana.eu.org
SMTP_PORT: "465"
SMTP_USERNAME: xxxx
SMTP_PASSWORD: 'xxxx'
SMTP_FROM_ADDRESS: [email protected]
SMTP_FROM_NAME: "ConfigurationCenterInfisical"

修改 values, 主要是 ingress, 镜像版本等。 redis 和 pg 用默认的不用修改。

1
2
3
4
5
6
7
8
9
10
11
12
ingress:
enabled: true
hostName: "infisical.k8s.grafana.eu.org"
ingressClassName: nginx # apisix
nginx:
enabled: false # 不搭建 ingress controller
annotations:
cert-manager.io/cluster-issuer: cloudflare-acme-cluster-issuer
tls:
- hosts:
- infisical.k8s.grafana.eu.org
secretName: infisical.k8s.grafana.eu.org.tls.secret # Cert-Manager 自动创建

生成的 ingress 规则

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
27
28
29
30
31
32
33
34
35
36
37
38
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
meta.helm.sh/release-name: infisical
meta.helm.sh/release-namespace: infisical
creationTimestamp: "2024-11-12T17:22:45Z"
generation: 2
labels:
app.kubernetes.io/managed-by: Helm
name: infisical-ingress
namespace: infisical
resourceVersion: "118331425"
uid: afa9bb9c-3d1d-4aae-9586-83179e092334
spec:
ingressClassName: nginx
rules:
- host: infisical.k8s.grafana.eu.org
http:
paths:
- backend:
service:
name: infisical-infisical-standalone-infisical
port:
number: 8080
path: /
pathType: Prefix
- backend:
service:
name: infisical-infisical-standalone-infisical
port:
number: 8080
path: /ss-webhook
pathType: Exact
tls:
- hosts:
- infisical.k8s.grafana.eu.org
secretName: infisical.k8s.grafana.eu.org.tls.secret

或者不创建 ingress ,使用 apisixroute

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
name: infisical-route
namespace: infisical
spec:
http:
- name: rule1
match:
hosts:
- infisical.k8s.grafana.eu.org
paths:
- "/*"
- "/ss-webhook"
backends:
- serviceName: infisical-infisical-standalone-infisical
servicePort: 8080
---
# 申请证书
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: infisical.k8s.grafana.eu.org.tls
namespace: infisical
spec:
secretName: infisical.k8s.grafana.eu.org.tls.secret
issuerRef:
name: cloudflare-acme-cluster-issuer # 使用 cert-manager 创建的 ClusterIssuer
kind: ClusterIssuer
commonName: infisical.k8s.grafana.eu.org
dnsNames:
- infisical.k8s.grafana.eu.org
---
# 使用证书
apiVersion: apisix.apache.org/v2
kind: ApisixTls
metadata:
name: infisical.k8s.grafana.eu.org.tls
namespace: infisical
spec:
hosts:
- infisical.k8s.grafana.eu.org
secret:
name: infisical.k8s.grafana.eu.org.tls.secret # the secret created by cert-manager
namespace: infisical

安装

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
helm upgrade -n infisical --install infisical infisical-helm-charts/infisical-standalone --values ./values.yaml 
Release "infisical" does not exist. Installing it now.
NAME: infisical
LAST DEPLOYED: Wed Dec 11 22:28:09 2024
NAMESPACE: infisical
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
##

-- Infisical Helm Chart --

██╗███╗ ██╗███████╗██╗███████╗██╗ ██████╗ █████╗ ██╗
██║████╗ ██║██╔════╝██║██╔════╝██║██╔════╝██╔══██╗██║
██║██╔██╗ ██║█████╗ ██║███████╗██║██║ ███████║██║
██║██║╚██╗██║██╔══╝ ██║╚════██║██║██║ ██╔══██║██║
██║██║ ╚████║██║ ██║███████║██║╚██████╗██║ ██║███████╗
╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═════╝╚═╝ ╚═╝╚══════╝
infisical-standalone (1.4.0)


╭―― Thank you for installing Infisical! 👋 ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――┤

│ Infisical / All-in-one open-source SecretOps solution to manage your secrets across your infra! 🔒🔑

│ Visit < https://infisical.com/docs/self-hosting/overview > for further documentation about self-hosting!

│ Current installation (infisical) :
│ • infisical : true
| • nginx : false
| • Postgres DB : true
| • Redis : true

╰―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――┤

――― Here's a list of helpful commands to get you started 📝 ―――――――――――――――――――――――――――――――――――――――――┤

→ Get all the Infisical resources (excluding secrets/pvcs)
$ kubectl get all -n infisical

→ Get your release status
$ helm status -n infisical infisical

→ Get your release resources
$ helm get all -n infisical infisical

→ Uninstall your release
$ helm uninstall -n infisical infisical

――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――┤

##

server端验证

infisical-dashboard

客户端使用

infisical创建clientid和key 。名称为 dev

infisical创建clientid和key

在客户端上

1
2
3
4
5
6
7
8
9
# 部署 operator
helm repo add infisical-helm-charts 'https://dl.cloudsmith.io/public/infisical/helm-charts/helm/charts/'

helm repo update

helm install infisical-secrets-operator infisical-helm-charts/secrets-operator -n infisical

# 配置身份凭证
kubectl apply -f infisical-universal-auth-credentials.yaml

infisical-universal-auth-credential.yaml

1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: Secret
metadata:
name: infisical-universal-auth-credentials
namespace: infisical
type: Opaque
# 或者使用 stringData
data:
clientId: xxxx # base64 加密
clientSecret: xxxx # base64 加密

获取 secret

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: secrets.infisical.com/v1alpha1
kind: InfisicalSecret
metadata:
name: test
namespace: default
spec:
hostAPI: https://infisical.k8s.grafana.eu.org/api
resyncInterval: 30
authentication:
universalAuth:
secretsScope:
projectSlug: test-project-i-yzv # 需要和网页上对应 (slug 的值)
envSlug: prod # 需要和网页上对应 (slug 的值)
secretsPath: "/test-dir" # 需要和网页上对应(所在文件夹)
recursive: false
credentialsRef:
secretName: infisical-universal-auth-credentials
secretNamespace: infisical
managedSecretReference:
secretName: test-env
secretNamespace: default
creationPolicy: "Orphan"

infisical项目目录

infisical-project中slug的值

查看, 已生成。未生成可以查看原因

1
2
3
imwl@ubuntu:~$ kubectl get secrets 
NAME TYPE DATA AGE
test-env Opaque 0 80s

查看日志

1
2
3
4
5
6
7
# kubectl describe infisicalsecrets.secrets.infisical.com  -n default test 

# kubectl logs -f -n infisical infisical-secre-controller-manager-585d556584-4tbhg

Manual re-sync interval set. Interval: 30s
unable to reconcile Infisical Secret because [err=
failed to get secrets because [err=APIError: CallListSecretsV3Raw unsuccessful response [GET https://infisical.k8s.grafana.eu.org/api/v3/secrets/raw?environment=prod&expandSecretReferences=true&include_imports=true&recursive=false&secretPath=%2Ftest-dir&workspaceId=&workspaceSlug=test-project-i-yzv] [status-code=403] [message="You are not allowed to access this resource"]]]. Will requeue after [requeueTime=30s]

需要加入到 project, 之前未加入

infisical-machineid添加到project

配置更新自动重启 secrets.infisical.com/auto-reload: “true”

1
2
3
4
5
6
7
8
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: test
namespace: default
annotations:
secrets.infisical.com/auto-reload: "true"

修改速率限制

当前为 infisical/infisical:v0.78.1-postgres, 其他版本改对应的位置

当项目变多时,会达到速率限制。使用原有镜像打包

当前使用的是 max: 1e10 即10的10次方,100亿

1
2
3
4
# cat Dockerfile 
FROM infisical/infisical:v0.78.1-postgres
COPY rateLimiter.mjs /backend/dist/server/config/rateLimiter.mjs
CMD ["./standalone-entrypoint.sh"]

rateLimiter.mjs

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });

// src/server/config/rateLimiter.ts
import { Redis } from "ioredis";
import { getConfig } from "../../lib/config/env.mjs";
var globalRateLimiterCfg = /* @__PURE__ */ __name(() => {
const appCfg = getConfig();
const redis = appCfg.isRedisConfigured ? new Redis(appCfg.REDIS_URL, {
connectTimeout: 500,
maxRetriesPerRequest: 1
}) : null;
return {
timeWindow: 60 * 1e3,
max: 1e10,
redis,
allowList: (req) => req.url === "/healthcheck" || req.url === "/api/status",
keyGenerator: (req) => req.realIp
};
}, "globalRateLimiterCfg");
var readLimit = {
timeWindow: 60 * 1e3,
hook: "preValidation",
max: 1e10,
keyGenerator: (req) => req.realIp
};
var writeLimit = {
timeWindow: 60 * 1e3,
hook: "preValidation",
max: 1e10,
keyGenerator: (req) => req.realIp
};
var secretsLimit = {
// secrets, folders, secret imports
timeWindow: 60 * 1e3,
hook: "preValidation",
max: 1e10,
keyGenerator: (req) => req.realIp
};
var authRateLimit = {
timeWindow: 60 * 1e3,
hook: "preValidation",
max: 1e10,
keyGenerator: (req) => req.realIp
};
var inviteUserRateLimit = {
timeWindow: 60 * 1e3,
hook: "preValidation",
max: 1e10,
keyGenerator: (req) => req.realIp
};
var mfaRateLimit = {
timeWindow: 60 * 1e3,
hook: "preValidation",
max: 1e10,
keyGenerator: (req) => {
return req.headers.authorization?.split(" ")[1] || req.realIp;
}
};
var publicEndpointLimit = {
// Read Shared Secrets
timeWindow: 60 * 1e3,
hook: "preValidation",
max: 1e10,
keyGenerator: (req) => req.realIp
};
var publicSecretShareCreationLimit = {
// Create Shared Secrets
timeWindow: 60 * 1e3,
max: 1e10,
keyGenerator: (req) => req.realIp
};
var userEngagementLimit = {
timeWindow: 60 * 1e3,
max: 1e10,
keyGenerator: (req) => req.realIp
};
export {
authRateLimit,
globalRateLimiterCfg,
inviteUserRateLimit,
mfaRateLimit,
publicEndpointLimit,
publicSecretShareCreationLimit,
readLimit,
secretsLimit,
userEngagementLimit,
writeLimit
};

修改功能限制

/backend/dist/ee/services/license/licence-fns.mjs

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });

// src/ee/services/license/licence-fns.ts
import axios from "axios";
import { getConfig } from "../../../lib/config/env.mjs";
import { request } from "../../../lib/config/request.mjs";
var getDefaultOnPremFeatures = /* @__PURE__ */ __name(() => ({
_id: null,
slug: null,
tier: 1, // 通常1表示一个启用的等级
workspaceLimit: 10000000000, // 或者设置为一个非常大的数字,表示无限制
workspacesUsed: 0,
memberLimit: 10000000000, // 或者设置为一个非常大的数字,表示无限制
membersUsed: 0,
environmentLimit: 100, // 或者设置为一个非常大的数字,表示无限制
environmentsUsed: 0,
identityLimit: 10000000000, // 或者设置为一个非常大的数字,表示无限制
identitiesUsed: 0,
dynamicSecret: true, // 启用动态密钥
secretVersioning: true, // 启用密钥版本管理
pitRecovery: true, // 启用 PIT 恢复
ipAllowlisting: true, // 启用 IP 白名单
rbac: true, // 启用基于角色的访问控制
customRateLimits: true, // 启用自定义速率限制
customAlerts: true, // 启用自定义警报
secretAccessInsights: true, // 启用密钥访问洞察
auditLogs: true, // 启用审计日志
auditLogsRetentionDays: 365, // 设置审计日志的保留天数
auditLogStreams: true, // 启用审计日志流
auditLogStreamLimit: 10000000000, // 设置审计日志流限制
samlSSO: true, // 启用 SAML 单点登录
hsm: true, // 启用硬件安全模块
oidcSSO: true, // 启用 OIDC 单点登录
scim: true, // 启用 SCIM(身份管理)
ldap: true, // 启用 LDAP
groups: true, // 启用组
status: "active", // 设置状态为激活
trial_end: null, // 无限制试用期
has_used_trial: false, // 未使用过试用
secretApproval: true, // 启用密钥审批
secretRotation: true, // 启用密钥轮换
caCrl: true, // 启用 CA CRL
instanceUserManagement: true, // 启用实例用户管理
externalKms: true, // 启用外部 KMS
rateLimits: {
readLimit: 10000000000, // 读取限制增加
writeLimit: 10000000000, // 写入限制增加
secretsLimit: 10000000000, // 密钥限制增加
}
}), "getDefaultOnPremFeatures");
var setupLicenceRequestWithStore = /* @__PURE__ */ __name((baseURL, refreshUrl, licenseKey) => {
let token;
const licenceReq = axios.create({
baseURL,
timeout: 35 * 1e3
});
const refreshLicence = /* @__PURE__ */ __name(async () => {
const appCfg = getConfig();
const { data: { token: authToken } } = await request.post(refreshUrl, {}, {
baseURL: appCfg.LICENSE_SERVER_URL,
headers: {
"X-API-KEY": licenseKey
}
});
token = authToken;
return token;
}, "refreshLicence");
licenceReq.interceptors.request.use((config) => {
if (token && config.headers) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
}, (err) => Promise.reject(err));
licenceReq.interceptors.response.use((response) => response, async (err) => {
const originalRequest = err.config;
if (err?.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
await refreshLicence();
licenceReq.defaults.headers.common.Authorization = `Bearer ${token}`;
return licenceReq(originalRequest);
}
return Promise.reject(err);
});
return {
request: licenceReq,
refreshLicence
};
}, "setupLicenceRequestWithStore");
export {
getDefaultOnPremFeatures,
setupLicenceRequestWithStore
};

/backend/dist/ee/services/license/__mocks__/licence-fns.mjs
第二个

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });

// src/ee/services/license/__mocks__/licence-fns.ts
var getDefaultOnPremFeatures = /* @__PURE__ */ __name(() => {
return {
_id: null,
slug: null,
tier: 1,
workspaceLimit: 10000000000,
workspacesUsed: 0,
memberLimit: 10000000000,
membersUsed: 0,
identityLimit: 10000000000,
identitiesUsed: 0,
environmentLimit: 10000000000,
environmentsUsed: 0,
secretVersioning: true,
pitRecovery: true,
ipAllowlisting: true,
rbac: true,
customRateLimits: true,
customAlerts: true,
auditLogs: true,
auditLogsRetentionDays: 365,
samlSSO: true,
scim: true,
ldap: true,
groups: true,
status: null,
trial_end: null,
has_used_trial: true,
secretApproval: true,
secretRotation: true,
caCrl: true
};
}, "getDefaultOnPremFeatures");
export {
getDefaultOnPremFeatures
};