Stay organized with collections
Save and categorize content based on your preferences.
When you create a database cluster, a server certificate that is signed by the
default GDC CA will be generated and configured for use
by your database server. To sign and upload a certificate for your database that
is issued by your own PKI, perform the following procedure. Your organization's
default issuer must be in BYO certificate mode to use this feature.
API
After you have created the database cluster and it is ready, save the
generated certificate signing request as a file.
Using the CSR and extension file, generate the certificate signed by your CA.
The code sample uses openssl but this step can be completed with other tools.
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Hard to understand","hardToUnderstand","thumb-down"],["Incorrect information or sample code","incorrectInformationOrSampleCode","thumb-down"],["Missing the information/samples I need","missingTheInformationSamplesINeed","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2025-08-25 UTC."],[],[],null,["# Sign and upload a server certificate\n\nWhen you create a database cluster, a server certificate that is signed by the\ndefault GDC CA will be generated and configured for use\nby your database server. To sign and upload a certificate for your database that\nis issued by your own PKI, perform the following procedure. Your organization's\ndefault issuer must be in BYO certificate mode to use this feature. \n\n### API\n\n1. After you have created the database cluster and it is ready, save the\n generated certificate signing request as a file.\n\n kubectl get certificate.pki.security.gdc.goog \\\n dbs-\u003cvar translate=\"no\"\u003eDBENGINE_SHORT_NAME\u003c/var\u003e-cert-request-\u003cvar translate=\"no\"\u003eDBCLUSTER_NAME\u003c/var\u003e \\\n -n \u003cvar translate=\"no\"\u003eUSER_PROJECT\u003c/var\u003e -o jsonpath='{.status.byoCertStatus.csrStatus.csr}' \\\n | base64 -d \u003e \u003cvar translate=\"no\"\u003eDBCLUSTER_NAME\u003c/var\u003e.csr\n\n2. Create a CSR extensions file containing the SANs for your database cluster.\n\n export SAN=$(openssl req -in \u003cvar translate=\"no\"\u003eDBCLUSTER_NAME\u003c/var\u003e.csr -noout -text | grep 'DNS:' | sed -s 's/^[ ]*//')\n\n echo \"keyUsage=digitalSignature,keyEncipherment\n extendedKeyUsage=serverAuth,clientAuth\n subjectAltName=${SAN:?}\" \u003e \u003cvar translate=\"no\"\u003eDBCLUSTER_NAME\u003c/var\u003e-csr.ext\n\n3. Using the CSR and extension file, generate the certificate signed by your CA.\n The code sample uses `openssl` but this step can be completed with other tools.\n\n openssl x509 -req -in \u003cvar translate=\"no\"\u003eDBCLUSTER_NAME\u003c/var\u003e.csr -days 365 \\\n -CA \u003cvar translate=\"no\"\u003eCA_CERTIFICATE_FILE\u003c/var\u003e -CAkey \u003cvar translate=\"no\"\u003eCA_PRIVATE_KEY_FILE\u003c/var\u003e \\\n -CAcreateserial -extfile \u003cvar translate=\"no\"\u003eDBCLUSTER_NAME\u003c/var\u003e-csr.ext \\\n -out \u003cvar translate=\"no\"\u003eDBCLUSTER_NAME\u003c/var\u003e-signed.crt\n\n4. Update the certificate resource with the signed certificate and CA\n certificate.\n\n echo \"spec:\n byoCertificate:\n certificate: $(base64 -w0 \u003cvar translate=\"no\"\u003eDBCLUSTER_NAME\u003c/var\u003e-signed.crt)\n ca: $(base64 -w0 \u003cvar translate=\"no\"\u003eCA_CERTIFICATE_FILE\u003c/var\u003e)\" \u003e patch.txt\n\n kubectl patch certificate.pki.security.gdc.goog \\\n dbs-\u003cvar translate=\"no\"\u003eDBENGINE_SHORT_NAME\u003c/var\u003e-cert-request-\u003cvar translate=\"no\"\u003eDBCLUSTER_NAME\u003c/var\u003e \\\n -n \u003cvar translate=\"no\"\u003eUSER_PROJECT\u003c/var\u003e --patch-file patch.txt --type='merge'\n\n5. Verify that the certificate has reached a ready state after the upload.\n\n kubectl get certificate.pki.security.gdc.goog \\\n dbs-\u003cvar translate=\"no\"\u003eDBENGINE_SHORT_NAME\u003c/var\u003e-cert-request-\u003cvar translate=\"no\"\u003eDBCLUSTER_NAME\u003c/var\u003e \\\n -n \u003cvar translate=\"no\"\u003eUSER_PROJECT\u003c/var\u003e -o json | jq -r ' .status.conditions[] | select( .type as $id | \"Ready\" | index($id))'\n\n The output should be similar to the following: \n\n {\n \"lastTransitionTime\": \"2024-05-03T08:42:10Z\",\n \"message\": \"Certificate is issued\",\n \"observedGeneration\": 2,\n \"reason\": \"Issued\",\n \"status\": \"True\",\n \"type\": \"Ready\"\n }\n\n6. Only if you are using an *Oracle* database, [stop and restart](/distributed-cloud/hosted/docs/latest/gdch/application/ao-user/db-start-stop-cluster)\n the database cluster so the listener's SSL configuration is reloaded.\n\nReplace the following:\n\n- \u003cvar translate=\"no\"\u003eDBENGINE_SHORT_NAME\u003c/var\u003e: the abbreviated name of the database engine. This is one of `al` (AlloyDB Omni), `pg` (PostgreSQL), or `ora` (Oracle).\n- \u003cvar translate=\"no\"\u003eDBCLUSTER_NAME\u003c/var\u003e: the name of the database cluster.\n- \u003cvar translate=\"no\"\u003eUSER_PROJECT\u003c/var\u003e: the name of the user project where the database cluster was created.\n- \u003cvar translate=\"no\"\u003eCA_CERTIFICATE_FILE\u003c/var\u003e: the path to the database CA certificate file.\n- \u003cvar translate=\"no\"\u003eCA_PRIVATE_KEY_FILE\u003c/var\u003e: the path to the database CA private key file."]]