@@ -70,34 +70,35 @@ func GetComponentAdditionalFiles(cfg *config.AppConfig, componentName string) (m
7070 // Define additional files for each component
7171 switch componentName {
7272 case "database/alloydb-omni" :
73- // AlloyDB Omni component files
74- deploymentPatch , err := generateAlloyDBDeploymentPatch (ctx )
73+ // AlloyDB Omni component files - only needed for preview environments
74+ // These files define the DBCluster CRD for AlloyDB Omni operator
75+ dbCluster , err := generateDBCluster (ctx )
7576 if err != nil {
7677 return nil , err
7778 }
78- files ["deployment-patch .yml" ] = deploymentPatch
79+ files ["dbcluster .yml" ] = dbCluster
7980
80- case "networking/gke-network-policy" :
81- // Network policy files
82- networkPolicy , err := generateNetworkPolicy (ctx )
81+ userAuth , err := generateUserAuthentication (ctx )
8382 if err != nil {
8483 return nil , err
8584 }
86- files ["network-policy .yml" ] = networkPolicy
85+ files ["user-authentication .yml" ] = userAuth
8786
88- dnsPolicy , err := generateDNSNetworkPolicy (ctx )
87+ case "networking/gke-network-policy" :
88+ // Network policy files - single comprehensive policy
89+ networkPolicy , err := generateNetworkPolicy (ctx )
8990 if err != nil {
9091 return nil , err
9192 }
92- files ["dns- network-policy.yml" ] = dnsPolicy
93+ files ["network-policy.yml" ] = networkPolicy
9394
9495 case "observability/autoscaling" :
9596 // HPA configuration
9697 hpa , err := generateHPA (ctx )
9798 if err != nil {
9899 return nil , err
99100 }
100- files ["hpa .yml" ] = hpa
101+ files ["horizontal-pod-autoscaler .yml" ] = hpa
101102
102103 // PodDisruptionBudget configuration
103104 pdb , err := generatePDB (ctx )
@@ -107,60 +108,93 @@ func GetComponentAdditionalFiles(cfg *config.AppConfig, componentName string) (m
107108 files ["pod-disruption-budget.yml" ] = pdb
108109
109110 case "security/workload-identity" :
110- // Service account patch
111- saPatch , err := generateServiceAccountPatch (ctx )
111+ // Service account with workload identity annotation
112+ sa , err := generateServiceAccount (ctx )
112113 if err != nil {
113114 return nil , err
114115 }
115- files ["service-account-patch.yml" ] = saPatch
116+ files ["service-account.yml" ] = sa
117+
118+ // External Secrets Operator SecretStore for Google Secret Manager
119+ ss , err := generateSecretStore (ctx )
120+ if err != nil {
121+ return nil , err
122+ }
123+ files ["secret-store.yml" ] = ss
116124 }
117125
118126 return files , nil
119127}
120128
121129// Helper functions to generate specific component files
122- func generateAlloyDBDeploymentPatch (ctx componentContext ) (string , error ) {
123- patch := `apiVersion: apps /v1
124- kind: Deployment
130+ func generateDBCluster (ctx componentContext ) (string , error ) {
131+ cluster := `apiVersion: alloydbomni.dbadmin.goog /v1
132+ kind: DBCluster
125133metadata:
126- name: ${APP_NAME} # from-param: ${APP_NAME}
134+ name: alloydb-preview
135+ namespace: ${NAMESPACE} # from-param: ${NAMESPACE}
136+ labels:
137+ app: alloydb-omni
138+ component: database
127139spec:
128- template:
129- spec:
130- containers:
131- - name: alloydb-omni
132- image: gcr.io/alloydb-omni/alloydbomni:16
133- env:
134- - name: POSTGRES_DB
135- value: ${DATABASE_NAME} # from-param: ${DATABASE_NAME}
136- - name: POSTGRES_USER
137- value: postgres
138- - name: POSTGRES_PASSWORD
139- valueFrom:
140- secretKeyRef:
141- name: ${APP_NAME}-database-secret # from-param: ${APP_NAME}-database-secret
142- key: password
143- - name: PGDATA
144- value: /var/lib/postgresql/data/pgdata
145- ports:
146- - containerPort: 5432
147- name: postgres
148- volumeMounts:
149- - name: postgres-storage
150- mountPath: /var/lib/postgresql/data
151- - name: dshm
152- mountPath: /dev/shm
153- volumes:
154- - name: postgres-storage
155- emptyDir: {}
156- - name: dshm
157- emptyDir:
158- medium: Memory
159- securityContext:
160- fsGroup: 999
140+ databaseVersion: "16.8.0"
141+ availability:
142+ numberOfStandbys: 0 # Explicitly disable HA for single-instance preview
143+ enableStandbyAsReadReplica: false
144+ primarySpec:
145+ adminUser:
146+ passwordRef:
147+ name: db-pw-alloydb-preview
148+ availabilityOptions:
149+ # Single instance configuration - no HA needed for preview
150+ livenessProbe: Enabled # Keep container health checks
151+ readinessProbe: Enabled
152+ resources:
153+ memory: 4Gi
154+ cpu: 2
155+ disk: 50Gi
156+ featureGates:
157+ enableSimulatedMaintenanceEvents: false
158+ `
159+
160+ tmpl , err := template .New ("dbcluster" ).Parse (cluster )
161+ if err != nil {
162+ return "" , err
163+ }
164+
165+ var buf bytes.Buffer
166+ if err := tmpl .Execute (& buf , ctx ); err != nil {
167+ return "" , err
168+ }
169+
170+ return buf .String (), nil
171+ }
172+
173+ func generateUserAuthentication (ctx componentContext ) (string , error ) {
174+ auth := `apiVersion: v1
175+ kind: ConfigMap
176+ metadata:
177+ name: alloydb-user-auth
178+ namespace: ${NAMESPACE} # from-param: ${NAMESPACE}
179+ data:
180+ pg_hba.conf: |
181+ # TYPE DATABASE USER ADDRESS METHOD
182+ local all all trust
183+ host all all 127.0.0.1/32 trust
184+ host all all ::1/128 trust
185+ host all all 0.0.0.0/0 md5
186+ ---
187+ apiVersion: v1
188+ kind: Secret
189+ metadata:
190+ name: db-pw-alloydb-preview
191+ namespace: ${NAMESPACE} # from-param: ${NAMESPACE}
192+ type: Opaque
193+ stringData:
194+ password: dev-password-123 # This should be replaced with a secure password
161195`
162196
163- tmpl , err := template .New ("alloydb-patch " ).Parse (patch )
197+ tmpl , err := template .New ("user-auth " ).Parse (auth )
164198 if err != nil {
165199 return "" , err
166200 }
@@ -212,91 +246,53 @@ spec:
212246 ports:
213247 - protocol: TCP
214248 port: 80
249+ # Allow DNS to node-local DNS cache (GKE uses NodeLocal DNSCache at 169.254.20.10)
250+ - to:
251+ - ipBlock:
252+ cidr: 169.254.20.10/32
253+ ports:
254+ - protocol: UDP
255+ port: 53
215256 - protocol: TCP
216- port: 443
217- # Allow DNS
257+ port: 53
258+ # Also allow DNS to kube-system namespace as fallback
218259 - to:
219260 - namespaceSelector:
220261 matchLabels:
221262 kubernetes.io/metadata.name: kube-system
222- - podSelector:
223- matchLabels:
224- k8s-app: kube-dns
225263 ports:
226264 - protocol: UDP
227265 port: 53
228266 - protocol: TCP
229267 port: 53
230- # Allow HTTPS to any destination
268+ # Allow HTTPS outbound
231269 - to:
232270 - ipBlock:
233271 cidr: 0.0.0.0/0
234272 ports:
235273 - protocol: TCP
236274 port: 443
237- # Allow database connections to private networks (RFC1918)
275+ # Allow database connections to private networks (for AlloyDB, Cloud SQL, etc.)
276+ # RFC1918 private address ranges where databases typically reside
238277 - to:
239278 - ipBlock:
240- cidr: 10.0.0.0/8
279+ cidr: 10.0.0.0/8 # Class A private
241280 - ipBlock:
242- cidr: 172.16.0.0/12
281+ cidr: 172.16.0.0/12 # Class B private
243282 - ipBlock:
244- cidr: 192.168.0.0/16
283+ cidr: 192.168.0.0/16 # Class C private
245284 ports:
246285 - protocol: TCP
247- port: 5432
286+ port: 5432 # PostgreSQL
248287 - protocol: TCP
249- port: 3306
250- `
251-
252- tmpl , err := template .New ("network-policy" ).Parse (policy )
253- if err != nil {
254- return "" , err
255- }
256-
257- var buf bytes.Buffer
258- if err := tmpl .Execute (& buf , ctx ); err != nil {
259- return "" , err
260- }
261-
262- return buf .String (), nil
263- }
264-
265- func generateDNSNetworkPolicy (ctx componentContext ) (string , error ) {
266- policy := `apiVersion: networking.k8s.io/v1
267- kind: NetworkPolicy
268- metadata:
269- name: ${APP_NAME}-dns-policy # from-param: ${NAME_PREFIX}${APP_NAME}-dns-policy
270- namespace: ${NAMESPACE} # from-param: ${NAMESPACE}
271- spec:
272- podSelector:
273- matchLabels:
274- app: ${APP_NAME} # from-param: ${APP_NAME}
275- policyTypes:
276- - Egress
277- egress:
278- # Allow DNS to GKE NodeLocal DNSCache
279- - to:
280- - ipBlock:
281- cidr: 169.254.20.10/32
282- ports:
283- - protocol: UDP
284- port: 53
288+ port: 5433 # AlloyDB Auth Proxy
285289 - protocol: TCP
286- port: 53
287- # Allow DNS to kube-system namespace as fallback
288- - to:
289- - namespaceSelector:
290- matchLabels:
291- kubernetes.io/metadata.name: kube-system
292- ports:
293- - protocol: UDP
294- port: 53
290+ port: 3306 # MySQL
295291 - protocol: TCP
296- port: 53
292+ port: 3307 # Cloud SQL MySQL
297293`
298294
299- tmpl , err := template .New ("dns -policy" ).Parse (policy )
295+ tmpl , err := template .New ("network -policy" ).Parse (policy )
300296 if err != nil {
301297 return "" , err
302298 }
@@ -309,6 +305,7 @@ spec:
309305 return buf .String (), nil
310306}
311307
308+
312309func generateHPA (ctx componentContext ) (string , error ) {
313310 hpa := `apiVersion: autoscaling/v2
314311kind: HorizontalPodAutoscaler
@@ -395,18 +392,52 @@ spec:
395392 return buf .String (), nil
396393}
397394
398- func generateServiceAccountPatch (ctx componentContext ) (string , error ) {
399- patch := `apiVersion: v1
395+ func generateServiceAccount (ctx componentContext ) (string , error ) {
396+ sa := `apiVersion: v1
400397kind: ServiceAccount
401398metadata:
402399 name: ${APP_NAME} # from-param: ${APP_NAME}
403400 namespace: ${NAMESPACE} # from-param: ${NAMESPACE}
401+ labels:
402+ app: ${APP_NAME} # from-param: ${APP_NAME}
403+ stage: ${STAGE} # from-param: ${STAGE}
404+ boundary: ${BOUNDARY} # from-param: ${BOUNDARY}
404405 annotations:
405- iam.gke.io/gcp-service-account: ${APP_NAME}-${STAGE}@${PROJECT_ID}.iam.gserviceaccount.com # from-param
406- automountServiceAccountToken: true
406+ iam.gke.io/gcp-service-account: ${APP_NAME}-k8s@${PROJECT_ID}.iam.gserviceaccount.com # from-param: ${APP_NAME}-k8s@${PROJECT_ID}.iam.gserviceaccount.com
407+ `
408+
409+ tmpl , err := template .New ("service-account" ).Parse (sa )
410+ if err != nil {
411+ return "" , err
412+ }
413+
414+ var buf bytes.Buffer
415+ if err := tmpl .Execute (& buf , ctx ); err != nil {
416+ return "" , err
417+ }
418+
419+ return buf .String (), nil
420+ }
421+
422+ func generateSecretStore (ctx componentContext ) (string , error ) {
423+ ss := `apiVersion: external-secrets.io/v1beta1
424+ kind: SecretStore
425+ metadata:
426+ name: ${APP_NAME}-secret-store # from-param: ${APP_NAME}-secret-store
427+ namespace: ${NAMESPACE} # from-param: ${NAMESPACE}
428+ spec:
429+ provider:
430+ gcpsm:
431+ projectID: ${PROJECT_ID} # from-param: ${PROJECT_ID}
432+ auth:
433+ workloadIdentity:
434+ clusterLocation: ${CLUSTER_LOCATION} # from-param: ${CLUSTER_LOCATION}
435+ clusterName: ${CLUSTER_NAME} # from-param: ${CLUSTER_NAME}
436+ serviceAccountRef:
437+ name: ${APP_NAME} # from-param: ${APP_NAME}
407438`
408439
409- tmpl , err := template .New ("sa-patch " ).Parse (patch )
440+ tmpl , err := template .New ("secret-store " ).Parse (ss )
410441 if err != nil {
411442 return "" , err
412443 }
0 commit comments