-
Notifications
You must be signed in to change notification settings - Fork 31
Expand file tree
/
Copy pathaws-secrets-manager.yaml
More file actions
217 lines (217 loc) · 7.33 KB
/
Copy pathaws-secrets-manager.yaml
File metadata and controls
217 lines (217 loc) · 7.33 KB
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# External Secrets Operator -> AWS Secrets Manager, for the plane-enterprise chart.
#
# Replace: NAMESPACE, REGION, ACCOUNT_ID, the secret names, and the release name in
# the ServiceAccount reference.
#
# Authentication uses EKS Pod Identity or IRSA on the External Secrets Operator's own
# ServiceAccount — no static keys. The IAM role needs
# secretsmanager:GetSecretValue + DescribeSecret on the secrets referenced below.
---
apiVersion: external-secrets.io/v1
kind: SecretStore
metadata:
name: aws-secrets-manager
namespace: NAMESPACE
spec:
provider:
aws:
service: SecretsManager
region: REGION
auth:
jwt:
serviceAccountRef:
# ESO's ServiceAccount, annotated with eks.amazonaws.com/role-arn
name: external-secrets
namespace: external-secrets
---
# 1. DATABASE — mirror the RDS-managed secret verbatim.
#
# An RDS managed-rotation secret contains only {"username", "password"}; a secret
# created by RDS for a non-master user also carries host/port/dbname. Either way,
# dataFrom.extract copies whatever keys exist straight through: no rewrite, no
# template, nothing to recompose when the password rotates.
#
# Chart side:
# external_secrets.database.secretName: plane-rds
# external_secrets.database.usernameKey: username
# external_secrets.database.passwordKey: password
# env.pgdb_host / pgdb_port / pgdb_name <- endpoint (not secret)
# If your secret carries the endpoint too, set hostKey/portKey/dbNameKey instead.
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: plane-rds
namespace: NAMESPACE
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: SecretStore
target:
name: plane-rds
creationPolicy: Owner
dataFrom:
- extract:
# The secret RDS created with the instance, e.g. rds!db-1234abcd-...
key: rds!db-REPLACE-ME
---
# 2. RABBITMQ (Amazon MQ) — same pattern.
#
# Chart side:
# external_secrets.rabbitmq.secretName: plane-amazonmq
# env.rabbitmq_host
# env.rabbitmq_port: '5671'
# env.rabbitmq_ssl: true <- REQUIRED: Amazon MQ refuses plaintext AMQP, and the
# discrete-parts path has no URL scheme to imply TLS.
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: plane-amazonmq
namespace: NAMESPACE
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: SecretStore
target:
name: plane-amazonmq
creationPolicy: Owner
dataFrom:
- extract:
key: plane/amazonmq
---
# 3. REDIS (ElastiCache auth token).
#
# Chart side (needs planeVersion v3.1.0+):
# external_secrets.redis.secretName: plane-elasticache
# external_secrets.redis.passwordKey: password
# env.redis_host, env.redis_ssl: true
#
# ElastiCache supports two simultaneously valid auth tokens — use that for
# zero-window rotation (see rotation-runbook.md).
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: plane-elasticache
namespace: NAMESPACE
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: SecretStore
target:
name: plane-elasticache
creationPolicy: Owner
dataFrom:
- extract:
key: plane/elasticache
---
# 4. OPENSEARCH — only needed when the domain uses basic auth.
#
# On AWS the better option is usually no secret at all: leave
# env.opensearch_remote_username / _password empty and external_secrets.opensearch
# unset, and the API authenticates to the domain with SigV4 using the pod's IAM role
# (serviceAccount.annotations). Use this only for a domain with the internal user
# database enabled.
#
# Chart side:
# external_secrets.opensearch.secretName: plane-opensearch
# env.opensearch_remote_url: https://search-plane.REGION.es.amazonaws.com
#
# Applies to the API workloads and the Plane AI workloads, which query the same domain.
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: plane-opensearch
namespace: NAMESPACE
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: SecretStore
target:
name: plane-opensearch
creationPolicy: Owner
dataFrom:
- extract:
key: plane/opensearch # {"username": "...", "password": "..."}
---
# 5. SHARED SIGNING KEYS — external_secrets.app_keys_existingSecret: plane-app-keys
#
# NEVER attach a rotation policy to this secret: SECRET_KEY and AES_SECRET_KEY/AES_SALT
# are key-encryption keys. Rotating them makes existing ciphertext undecryptable, and
# the failure is silent.
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: plane-app-keys
namespace: NAMESPACE
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: SecretStore
target:
name: plane-app-keys
creationPolicy: Owner
data:
- secretKey: SECRET_KEY
remoteRef: { key: plane/app-keys, property: SECRET_KEY }
- secretKey: AES_SECRET_KEY
remoteRef: { key: plane/app-keys, property: AES_SECRET_KEY }
- secretKey: AES_SALT
remoteRef: { key: plane/app-keys, property: AES_SALT }
- secretKey: LIVE_SERVER_SECRET_KEY
remoteRef: { key: plane/app-keys, property: LIVE_SERVER_SECRET_KEY }
- secretKey: PI_INTERNAL_SECRET
remoteRef: { key: plane/app-keys, property: PI_INTERNAL_SECRET }
- secretKey: SILO_HMAC_SECRET_KEY
remoteRef: { key: plane/app-keys, property: SILO_HMAC_SECRET_KEY }
- secretKey: CURSOR_WEBHOOK_SECRET
remoteRef: { key: plane/app-keys, property: CURSOR_WEBHOOK_SECRET }
---
# 6. SILO — the one place a composed DSN is still needed.
#
# Silo, live and Plane AI read a connection URL rather than discrete parts, so here ESO
# builds the URL from the mirrored RDS secret with a template. Note urlEncode on the
# password: a generated password containing @ : / # would otherwise break the URL.
#
# Chart side: external_secrets.silo_env_existingSecret: plane-silo-env
# This Secret replaces the chart's silo Secret entirely, so it must also carry the
# connector OAuth secrets you use (GITHUB_CLIENT_SECRET, SLACK_CLIENT_SECRET, ...).
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: plane-silo-env
namespace: NAMESPACE
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: SecretStore
target:
name: plane-silo-env
creationPolicy: Owner
template:
engine: v2
data:
DATABASE_URL: >-
postgresql://{{ .username }}:{{ .password | urlEncode }}@plane.abc123.REGION.rds.amazonaws.com:5432/plane?sslmode=require
AMQP_URL: >-
amqps://{{ .mq_username }}:{{ .mq_password | urlEncode }}@b-1.plane.mq.REGION.amazonaws.com:5671/
REDIS_URL: >-
rediss://:{{ .redis_password | urlEncode }}@plane.abc.cache.amazonaws.com:6379
GITHUB_CLIENT_SECRET: '{{ .github_client_secret }}'
data:
- secretKey: username
remoteRef: { key: rds!db-REPLACE-ME, property: username }
- secretKey: password
remoteRef: { key: rds!db-REPLACE-ME, property: password }
- secretKey: mq_username
remoteRef: { key: plane/amazonmq, property: username }
- secretKey: mq_password
remoteRef: { key: plane/amazonmq, property: password }
- secretKey: redis_password
remoteRef: { key: plane/elasticache, property: password }
- secretKey: github_client_secret
remoteRef: { key: plane/connectors, property: github_client_secret }