🌳
pt0/deployF/servicesF/syncVaultWardenF.mts
1import { envHToA } from '../k8sF/envHToAF.mts'
4import * as _ from 'lodash-es'
5import type { V1Volume, V1Container } from '@kubernetes/client-node'
20export const k8sVaultwarden = async ({hostname, name='bitwarden', withLitestream=false}: {
21 hostname: string, name?: string, withLitestream?: boolean,
22}) => {
23 const {cluster_name} = getKlusterCtx()
24 const action = getAction()
25 const portNo = 80
27 const {volumes: pvcVolumes, volumeMounts: pvcMounts} = pvcVolumeMounts({name, mountPath: '/data'})
28 const secretName = tsSec('bitwardenvault-admintoken')
29 await genPlainSecretIfMissing({secretName, autoYes: true})
31 const volumes: V1Volume[] = [...pvcVolumes]
32 const containers: V1Container[] = [{
33 name, image: 'vaultwarden/server:1.37.1', // 260802
34 volumeMounts: pvcMounts,
35 env: [
36 {
37 name: 'ADMIN_TOKEN',
38 valueFrom: {
39 secretKeyRef: {
40 name, key: secretName
41 }
42 }
43 },
44 ...envHToA({
45 SIGNUPS_ALLOWED: 'false', // can be overriden in /admin ?
46 }),
47 ]
48 }]
50 const annotations: Record<string, string> = {}
51 // configmap+secret always created so vwrestore works on any cluster (standby/restore targets
52 // don't run the sidecar but still need the litestream config + haS3 creds to restore)
53 const {configMap, secret, configVolName, configMount, configHash} = vwLitestreamResources({name, cluster_name})
54 if (withLitestream) {
55 volumes.push({name: configVolName, configMap: {name: configMap.metadata.name}})
56 containers.push({
57 name: 'litestream', image: litestreamImg,
58 args: ['replicate', '-config', vwLitestreamConfigFile],
59 volumeMounts: [...pvcMounts, configMount],
60 envFrom: vwLitestreamEnvFrom(name),
61 })
62 // rclone sidecar: additive copy of attachments/sends/rsa_key -> haS3 (litestream covers db only)
63 containers.push({
64 name: 'rclone', image: rcloneImg,
65 command: ['/bin/sh', '-c'], args: [vwRcloneCopyUpCmd()],
66 volumeMounts: pvcMounts,
67 env: envHToA(vwRcloneEnvH({cluster_name})),
68 })
69 annotations['litestream-config-hash'] = configHash
70 }
72 const resources = _.compact([
73 secretFileTemplate({name: secretName, kubeName: name}),
75 volumes, name,
76 strategy: {type: 'Recreate'},
77 containers,
78 annotations: _.isEmpty(annotations) ? undefined : annotations,
79 }),
80 kubeSvcTmpl({name, portNo}),
81 genericIngressTmpl({name, hostname, portNo}),
82 configMap,
83 secret,
84 ])
86 await Promise.all([
87 resourcesAction({resources, action, cluster_name}),
88 kubeActionPvc({action, cluster_name, name, sizeGb: 10})
89 ])
91 if (_.includes(['info', 'apply'], action)) {
92 const manageUrl = `${hostname}/admin`
93 betLog({manageUrl, adminDashPass: getPlainNoMappedSec(secretName), dbPath: vwDbPath, withLitestream})
94 }