[{"data":1,"prerenderedAt":796},["ShallowReactive",2],{"navigation_docs":3,"-configure-secrets":136,"-configure-secrets-surround":791},[4,26,47,68,89,110,123],{"title":5,"path":6,"stem":7,"children":8,"page":25},"Getting Started","\u002Fgetting-started","1.getting-started",[9,13,17,21],{"title":10,"path":11,"stem":12},"What you are running","\u002Fgetting-started\u002Fwhat-you-are-running","1.getting-started\u002F1.what-you-are-running",{"title":14,"path":15,"stem":16},"Architecture","\u002Fgetting-started\u002Farchitecture","1.getting-started\u002F2.architecture",{"title":18,"path":19,"stem":20},"Prerequisites","\u002Fgetting-started\u002Fprerequisites","1.getting-started\u002F3.prerequisites",{"title":22,"path":23,"stem":24},"Quickstart","\u002Fgetting-started\u002Fquickstart","1.getting-started\u002F4.quickstart",false,{"title":27,"path":28,"stem":29,"children":30,"page":25},"Install","\u002Finstall","2.install",[31,35,39,43],{"title":32,"path":33,"stem":34},"Install the chart","\u002Finstall\u002Finstall-the-chart","2.install\u002F1.install-the-chart",{"title":36,"path":37,"stem":38},"Activation","\u002Finstall\u002Factivation","2.install\u002F2.activation",{"title":40,"path":41,"stem":42},"DNS and TLS","\u002Finstall\u002Fdns-and-tls","2.install\u002F3.dns-and-tls",{"title":44,"path":45,"stem":46},"Verify your install","\u002Finstall\u002Fverify-your-install","2.install\u002F4.verify-your-install",{"title":48,"path":49,"stem":50,"children":51,"page":25},"Configure","\u002Fconfigure","3.configure",[52,56,60,64],{"title":53,"path":54,"stem":55},"Data services","\u002Fconfigure\u002Fdata-services","3.configure\u002F1.data-services",{"title":57,"path":58,"stem":59},"Secrets","\u002Fconfigure\u002Fsecrets","3.configure\u002F2.secrets",{"title":61,"path":62,"stem":63},"Registry and air-gapped installs","\u002Fconfigure\u002Fregistry-and-airgap","3.configure\u002F3.registry-and-airgap",{"title":65,"path":66,"stem":67},"Integrations","\u002Fconfigure\u002Fintegrations","3.configure\u002F4.integrations",{"title":69,"path":70,"stem":71,"children":72,"page":25},"Licensing","\u002Flicensing","4.licensing",[73,77,81,85],{"title":74,"path":75,"stem":76},"How licensing works","\u002Flicensing\u002Fhow-licensing-works","4.licensing\u002F1.how-licensing-works",{"title":78,"path":79,"stem":80},"Your key never leaves","\u002Flicensing\u002Fyour-key-never-leaves","4.licensing\u002F2.your-key-never-leaves",{"title":82,"path":83,"stem":84},"What phones home","\u002Flicensing\u002Fwhat-phones-home","4.licensing\u002F3.what-phones-home",{"title":86,"path":87,"stem":88},"Revoke and recover","\u002Flicensing\u002Frevoke-and-recover","4.licensing\u002F4.revoke-and-recover",{"title":90,"path":91,"stem":92,"children":93,"page":25},"Operate","\u002Foperate","5.operate",[94,98,102,106],{"title":95,"path":96,"stem":97},"Upgrade","\u002Foperate\u002Fupgrade","5.operate\u002F1.upgrade",{"title":99,"path":100,"stem":101},"Backup and restore","\u002Foperate\u002Fbackup-and-restore","5.operate\u002F2.backup-and-restore",{"title":103,"path":104,"stem":105},"Observability","\u002Foperate\u002Fobservability","5.operate\u002F3.observability",{"title":107,"path":108,"stem":109},"High availability","\u002Foperate\u002Fhigh-availability","5.operate\u002F4.high-availability",{"title":111,"path":112,"stem":113,"children":114,"page":25},"Troubleshooting","\u002Ftroubleshooting","6.troubleshooting",[115,119],{"title":116,"path":117,"stem":118},"Install failures","\u002Ftroubleshooting\u002Finstall-failures","6.troubleshooting\u002F1.install-failures",{"title":120,"path":121,"stem":122},"Licensing failures","\u002Ftroubleshooting\u002Flicensing-failures","6.troubleshooting\u002F2.licensing-failures",{"title":124,"path":125,"stem":126,"children":127,"page":25},"Reference","\u002Freference","9.reference",[128,132],{"title":129,"path":130,"stem":131},"Helm values","\u002Freference\u002Fhelm-values","9.reference\u002F1.helm-values",{"title":133,"path":134,"stem":135},"Environment variables","\u002Freference\u002Fenvironment","9.reference\u002F2.environment",{"id":137,"title":57,"body":138,"description":785,"extension":786,"links":787,"meta":788,"navigation":348,"path":58,"seo":789,"stem":59,"__hash__":790},"docs\u002F3.configure\u002F2.secrets.md",{"type":139,"value":140,"toc":776},"minimark",[141,145,154,159,162,266,277,282,285,295,298,302,305,417,439,446,450,457,470,496,503,662,666,669,679,699,706,712,719,755,764,772],[142,143,57],"h1",{"id":144},"secrets",[146,147,148,149,153],"p",{},"Every credential the platform runs on lives in one Kubernetes Secret in your namespace, named ",[150,151,152],"code",{},"\u003Crelease>-platform-env",". The API reads its whole environment from it; the auth service, the email worker and the web tier each pull the specific keys they need. The license agent reads and writes it through the Kubernetes API. Nothing in the chart talks to a secret store, and nothing leaves your cluster.",[155,156,158],"h2",{"id":157},"what-the-chart-generates","What the chart generates",[146,160,161],{},"On a first install, with no values set, the chart mints these and writes them into that Secret:",[163,164,165,178],"table",{},[166,167,168],"thead",{},[169,170,171,175],"tr",{},[172,173,174],"th",{},"Key",[172,176,177],{},"What it is",[179,180,181,196,206,220,233,243,253],"tbody",{},[169,182,183,189],{},[184,185,186],"td",{},[150,187,188],{},"JWT_SECRET",[184,190,191,192,195],{},"Signs session tokens. The auth container gets the same value as its ",[150,193,194],{},"GOTRUE_JWT_SECRET",".",[169,197,198,203],{},[184,199,200],{},[150,201,202],{},"POSTGRES_PASSWORD",[184,204,205],{},"The platform's database role.",[169,207,208,213],{},[184,209,210],{},[150,211,212],{},"AUTH_ADMIN_PASSWORD",[184,214,215,216,219],{},"The ",[150,217,218],{},"supabase_auth_admin"," role the auth service connects as.",[169,221,222,227],{},[184,223,224],{},[150,225,226],{},"CACHE_PASSWORD",[184,228,229,230,195],{},"The bundled Redis, when ",[150,231,232],{},"redis.mode=bundled",[169,234,235,240],{},[184,236,237],{},[150,238,239],{},"NUXT_SESSION_PASSWORD",[184,241,242],{},"The web tier's session cookie key.",[169,244,245,250],{},[184,246,247],{},[150,248,249],{},"DEPLOYMENTS_SERVICE_KEY",[184,251,252],{},"The API key this platform presents to its own downstream deployments. Only relevant if you are an MVNE provisioning MVNOs.",[169,254,255,260],{},[184,256,257],{},[150,258,259],{},"GOTRUE_HOOK_SEND_EMAIL_SECRETS",[184,261,262,263,195],{},"Signs the auth service's send-email webhook. Generated only when ",[150,264,265],{},"auth.emailHook.enabled=true",[146,267,268,269,272,273,276],{},"You can supply any of them instead. ",[150,270,271],{},"secrets.jwtSecret"," and ",[150,274,275],{},"app.sessionPassword"," take a value directly; the database and cache passwords come from your own DSN when the service is external.",[278,279,281],"h3",{"id":280},"upgrades-never-rotate-a-live-credential","Upgrades never rotate a live credential",[146,283,284],{},"Before generating anything, the chart looks up the Secret already in the namespace and reuses every key it finds. A fresh random value is only minted for a key that is not there yet.",[146,286,287,288,291,292,294],{},"That is what makes ",[150,289,290],{},"helm upgrade"," safe. Postgres was initialised with a password on day one and will not change its mind; if an upgrade re-generated ",[150,293,202],{},", the DSN in the Secret would stop matching the database and the platform would fail to connect. The lookup means an upgrade cannot pull a credential out from under a running deployment, no matter how many times you run it or which flags you pass.",[146,296,297],{},"The corollary: deleting a key from the Secret by hand makes the next upgrade generate a new one. That is the only way to rotate, and for the database password it is not enough on its own, because the database still holds the old one.",[155,299,301],{"id":300},"the-at-rest-encryption-key","The at-rest encryption key",[146,303,304],{},"The platform encrypts the credentials it stores for you (supplier API keys, payment keys, per-tenant secrets) with an age key before they go into the database. Helm cannot generate an X25519 keypair, so the chart does not: you generate one and pass it in.",[306,307,312],"pre",{"className":308,"code":309,"language":310,"meta":311,"style":311},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","age-keygen -o key.txt\n# public key: age1qyq...   \u003C- the recipient\n# the file's AGE-SECRET-KEY-... line is the identity\n\nhelm upgrade --install my-mvno oci:\u002F\u002Fghcr.io\u002Fsolvegio\u002Fcharts\u002Fplatform --version \u003Cversion> \\\n  --namespace my-mvno \\\n  --set secrets.kek.recipient=age1qyq... \\\n  --set secrets.kek.identity=AGE-SECRET-KEY-...\n","bash","",[150,313,314,330,337,343,350,388,398,409],{"__ignoreMap":311},[315,316,319,323,327],"span",{"class":317,"line":318},"line",1,[315,320,322],{"class":321},"sBMFI","age-keygen",[315,324,326],{"class":325},"sfazB"," -o",[315,328,329],{"class":325}," key.txt\n",[315,331,333],{"class":317,"line":332},2,[315,334,336],{"class":335},"sHwdD","# public key: age1qyq...   \u003C- the recipient\n",[315,338,340],{"class":317,"line":339},3,[315,341,342],{"class":335},"# the file's AGE-SECRET-KEY-... line is the identity\n",[315,344,346],{"class":317,"line":345},4,[315,347,349],{"emptyLinePlaceholder":348},true,"\n",[315,351,353,356,359,362,365,368,371,375,378,382,385],{"class":317,"line":352},5,[315,354,355],{"class":321},"helm",[315,357,358],{"class":325}," upgrade",[315,360,361],{"class":325}," --install",[315,363,364],{"class":325}," my-mvno",[315,366,367],{"class":325}," oci:\u002F\u002Fghcr.io\u002Fsolvegio\u002Fcharts\u002Fplatform",[315,369,370],{"class":325}," --version",[315,372,374],{"class":373},"sMK4o"," \u003C",[315,376,377],{"class":325},"versio",[315,379,381],{"class":380},"sTEyZ","n",[315,383,384],{"class":373},">",[315,386,387],{"class":380}," \\\n",[315,389,391,394,396],{"class":317,"line":390},6,[315,392,393],{"class":325},"  --namespace",[315,395,364],{"class":325},[315,397,387],{"class":380},[315,399,401,404,407],{"class":317,"line":400},7,[315,402,403],{"class":325},"  --set",[315,405,406],{"class":325}," secrets.kek.recipient=age1qyq...",[315,408,387],{"class":380},[315,410,412,414],{"class":317,"line":411},8,[315,413,403],{"class":325},[315,415,416],{"class":325}," secrets.kek.identity=AGE-SECRET-KEY-...\n",[146,418,419,422,423,426,427,430,431,434,435,438],{},[150,420,421],{},"secrets.kek.recipient"," is the public half and lands in the ConfigMap as ",[150,424,425],{},"SECRETS_KEK_AGE_RECIPIENT",". ",[150,428,429],{},"secrets.kek.identity"," is the private half and lands in the Secret as ",[150,432,433],{},"SECRETS_KEK_AGE_IDENTITY",". You need the identity to read back anything the recipient encrypted, so keep a copy of ",[150,436,437],{},"key.txt"," somewhere you will still have it after a disaster. Losing it means losing every credential the platform stored.",[146,440,441,445],{},[442,443,444],"strong",{},"Leave them unset and the platform still boots."," It falls back to a pass-through codec and writes those credentials to the database in plain text, saying so loudly in the API logs on every start. Nothing warns you again after that. Set the keypair before you put a real supplier or payment credential into the platform, because switching the codec on later does not re-encrypt what is already there.",[155,447,449],{"id":448},"bringing-your-own-secret","Bringing your own Secret",[146,451,452,453,456],{},"If your secrets come from SOPS, sealed-secrets, Vault or External Secrets Operator, set ",[150,454,455],{},"secrets.existingSecret"," and the chart renders no Secret of its own. Every reference in every template points at the name you gave.",[306,458,460],{"className":308,"code":459,"language":310,"meta":311,"style":311},"--set secrets.existingSecret=my-mvno-secrets\n",[150,461,462],{"__ignoreMap":311},[315,463,464,467],{"class":317,"line":318},[315,465,466],{"class":321},"--set",[315,468,469],{"class":325}," secrets.existingSecret=my-mvno-secrets\n",[146,471,472,473,476,477,272,480,483,484,488,489,492,493,495],{},"Your Secret has to carry every key the chart would otherwise have generated, plus ",[150,474,475],{},"DB_DSN",", ",[150,478,479],{},"AUTH_DATABASE_URL",[150,481,482],{},"ACTIVATION_CODE",". The ",[485,486,487],"a",{"href":134},"environment reference"," lists them all with their shapes. ",[150,490,491],{},"activation.code"," stops being a required Helm value in this mode, because the chart is no longer the thing writing it: the license agent reads ",[150,494,482],{}," out of the Secret object directly.",[146,497,498,499,502],{},"With External Secrets Operator, point an ",[150,500,501],{},"ExternalSecret"," at that same name and let it materialise the Secret before you install:",[306,504,508],{"className":505,"code":506,"language":507,"meta":311,"style":311},"language-yaml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","apiVersion: external-secrets.io\u002Fv1\nkind: ExternalSecret\nmetadata:\n  name: my-mvno-secrets\nspec:\n  secretStoreRef: { name: my-vault, kind: ClusterSecretStore }\n  target:\n    name: my-mvno-secrets      # == secrets.existingSecret\n    creationPolicy: Owner\n    deletionPolicy: Retain\n  dataFrom:\n    - extract: { key: solvegio\u002Fmy-mvno }\n","yaml",[150,509,510,522,532,540,550,557,589,596,609,620,631,639],{"__ignoreMap":311},[315,511,512,516,519],{"class":317,"line":318},[315,513,515],{"class":514},"swJcz","apiVersion",[315,517,518],{"class":373},":",[315,520,521],{"class":325}," external-secrets.io\u002Fv1\n",[315,523,524,527,529],{"class":317,"line":332},[315,525,526],{"class":514},"kind",[315,528,518],{"class":373},[315,530,531],{"class":325}," ExternalSecret\n",[315,533,534,537],{"class":317,"line":339},[315,535,536],{"class":514},"metadata",[315,538,539],{"class":373},":\n",[315,541,542,545,547],{"class":317,"line":345},[315,543,544],{"class":514},"  name",[315,546,518],{"class":373},[315,548,549],{"class":325}," my-mvno-secrets\n",[315,551,552,555],{"class":317,"line":352},[315,553,554],{"class":514},"spec",[315,556,539],{"class":373},[315,558,559,562,564,567,570,572,575,578,581,583,586],{"class":317,"line":390},[315,560,561],{"class":514},"  secretStoreRef",[315,563,518],{"class":373},[315,565,566],{"class":373}," {",[315,568,569],{"class":514}," name",[315,571,518],{"class":373},[315,573,574],{"class":325}," my-vault",[315,576,577],{"class":373},",",[315,579,580],{"class":514}," kind",[315,582,518],{"class":373},[315,584,585],{"class":325}," ClusterSecretStore",[315,587,588],{"class":373}," }\n",[315,590,591,594],{"class":317,"line":400},[315,592,593],{"class":514},"  target",[315,595,539],{"class":373},[315,597,598,601,603,606],{"class":317,"line":411},[315,599,600],{"class":514},"    name",[315,602,518],{"class":373},[315,604,605],{"class":325}," my-mvno-secrets",[315,607,608],{"class":335},"      # == secrets.existingSecret\n",[315,610,612,615,617],{"class":317,"line":611},9,[315,613,614],{"class":514},"    creationPolicy",[315,616,518],{"class":373},[315,618,619],{"class":325}," Owner\n",[315,621,623,626,628],{"class":317,"line":622},10,[315,624,625],{"class":514},"    deletionPolicy",[315,627,518],{"class":373},[315,629,630],{"class":325}," Retain\n",[315,632,634,637],{"class":317,"line":633},11,[315,635,636],{"class":514},"  dataFrom",[315,638,539],{"class":373},[315,640,642,645,648,650,652,655,657,660],{"class":317,"line":641},12,[315,643,644],{"class":373},"    -",[315,646,647],{"class":514}," extract",[315,649,518],{"class":373},[315,651,566],{"class":373},[315,653,654],{"class":514}," key",[315,656,518],{"class":373},[315,658,659],{"class":325}," solvegio\u002Fmy-mvno",[315,661,588],{"class":373},[278,663,665],{"id":664},"the-license-agent-writes-into-that-secret-too","The license agent writes into that Secret too",[146,667,668],{},"This is the part that bites people, so it gets its own heading.",[146,670,671,672,272,675,678],{},"The license agent holds ",[150,673,674],{},"get",[150,676,677],{},"patch"," on that one Secret, by name, and nothing else in the cluster. It owns six keys in it, and writes them on first enrollment and again on every renewal and key rotation for as long as the deployment runs:",[146,680,681,476,684,476,687,476,690,476,693,476,696,195],{},[150,682,683],{},"SIGNING_SEED",[150,685,686],{},"POP_SIGNING_SEED",[150,688,689],{},"PARENT_LEASE_TOKEN",[150,691,692],{},"PARENT_BASE_URL",[150,694,695],{},"REQUIRE_PARENT_LEASE",[150,697,698],{},"ACTIVATION_CODE_CONSUMED",[146,700,701,702,705],{},"A revoked deployment picks up a seventh, ",[150,703,704],{},"LEASE_STATUS",", which the agent clears again when it recovers. That is the whole of what it writes. Everything else in the Secret is yours or the chart's.",[146,707,708,711],{},[442,709,710],{},"The agent is the source of truth for those keys, not your secret store."," The signing seed is generated inside your cluster and has no copy anywhere else, including with us. The lease token is a fresh signed credential the agent fetches and persists on a schedule. If your pipeline reconciles the Secret back to what your store thinks it should contain, it reverts the lease the agent just wrote, and the API stops serving on the next check.",[146,713,714,715,718],{},"So: whatever supplies the Secret must ",[442,716,717],{},"retain"," keys it did not create.",[720,721,722,734,741],"ul",{},[723,724,725,726,729,730,733],"li",{},"With ESO, ",[150,727,728],{},"creationPolicy: Owner"," plus ",[150,731,732],{},"deletionPolicy: Retain",", as above. Do not turn on a sync policy that prunes keys ESO did not put there. ESO's default merge behaviour already leaves them alone; the danger is a policy that replaces the Secret wholesale.",[723,735,736,737,740],{},"With sealed-secrets, do not apply a ",[150,738,739],{},"SealedSecret"," that recreates the Secret from scratch after the agent has enrolled.",[723,742,743,744,747,748,751,752,195],{},"With SOPS and a plain ",[150,745,746],{},"kubectl apply",", use ",[150,749,750],{},"apply"," and not ",[150,753,754],{},"replace",[146,756,757,758,760,761,763],{},"Do not put ",[150,759,683],{}," or ",[150,762,689],{}," into your secret store as literal values and expect them to work. A lease has an expiry and is rotated; a copied one goes stale. Let the agent own them.",[146,765,766,768,769,771],{},[485,767,78],{"href":79}," explains what the signing seed is and why it is generated where it is. If the API is stuck waiting on a lease, ",[485,770,120],{"href":121}," is the page you want.",[773,774,775],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}",{"title":311,"searchDepth":318,"depth":332,"links":777},[778,781,782],{"id":157,"depth":332,"text":158,"children":779},[780],{"id":280,"depth":339,"text":281},{"id":300,"depth":332,"text":301},{"id":448,"depth":332,"text":449,"children":783},[784],{"id":664,"depth":339,"text":665},"What the chart generates, why an upgrade never rotates it, and how to bring your own Secret from SOPS, sealed-secrets or External Secrets Operator.","md",null,{},{"title":57,"description":785},"2wY86k5xgeNlrZJy7kNwNgqaDEILPmTCZDqf280KgLs",[792,794],{"title":53,"path":54,"stem":55,"description":793,"children":-1},"Postgres and Kafka run under an operator by default, or point them at a managed service. Redis is the one service the chart still runs itself.",{"title":61,"path":62,"stem":63,"description":795,"children":-1},"Pinning images by digest, mirroring the image set into your own registry, and pulling from a private one.",1783967741116]