Introduction
When developing applications, using environment variables is essential. They help configure values for different environments like development, staging, and production. Some environment variables, such as API keys, database connections, or passwords, are sensitive and need to be kept secure. If you're using Google Cloud, their Key Management Service (KMS) can help you manage keys, and allows you to encrypt and decrypt values using those keys.
Prerequisites
Before we proceed, make sure you have:
Key Management Service
KMS works with key rings, which hold multiple keys. You use these keys to encrypt and decrypt string values or file data.
Be cautious: if a key is deleted, any data encrypted with it can't be decrypted anymore.
To create a key ring, execute the following command:
gcloud kms keyrings create "key-ring-name" \
--location "global"
Then create a key based on the keyring.
gcloud kms keys create "key-name" \
--location "global" \
--keyring "key-ring-name" \
--purpose "encryption"
You can check the keyring and key that were created by using a command or by visiting the Google Cloud Console.
gcloud kms keys list \
--location "global" \
--keyring "key-ring-name"
gcloud kms keys versions list \
--location "global" \
--keyring "key-ring-name" \
--key "key-name"
Deploying with NodeJS
Once you've successfully set up your NodeJS Typescript project, install the following package:
yarn add @google-cloud/kms
Use the following code block to interact with Google KMS.
import {KeyManagementServiceClient} from '@google-cloud/kms'
const projectId = 'project-id'
const location = 'global'
const keyRing = 'key-ring-name' // replace your keyring name
const cryptoKey = 'key-name' // replace your key name
const kmsClient = new KeyManagementServiceClient()
const parent = kmsClient.locationPath(projectId, location)
const kmsPath = kmsClient.cryptoKeyPath(projectId, location, keyRing, cryptoKey)
const [keyRings] = await kmsClient.listKeyRings({parent})
const decrypt = async (encryptValue: string): Promise<string> => {
try {
const request = {
name: kmsPath,
ciphertext: encryptValue,
}
const [decryptedText] = await kmsClient.decrypt(request)
return decryptedText.plaintext.toString().trim()
} catch (e) {
console.error(e)
return null
}
}
if (keyRings.length) {
const keyRingNames = keyRings.map(keyRing => keyRing.name)
console.log('Key rings:', keyRingNames)
}
const [username, password] = await Promise.all([decrypt(process.env.GCP_USERNAME), decrypt(process.env.GCP_PASSWORD)])
console.log('Decrypted value:', username, password)
I use `process.env.GCP_USERNAME` and `process.env.GCP_PASSWORD` defined in the `.env` file like this
GCP_USERNAME=CiQAgHBm4/HepIf4wK9keDAYTenhPTA5lgJOOXEziBNdjiZ14SwSOABot+e3PRhP8Tepqb8QvvmD9yPcOuBNt5Goh0404pHqpcs1/sCagzYhhnEvn71gYY3GDps0CzK2
GCP_PASSWORD=CiQAgHBm74TCT5a66lD0Q0L1k/k0IP4y2zPCmia0VBB76blzxmUSOABot+e2hvUl91xbUvuSvUVYKtrqDlw8+qTM3d+1Mw6j+WpsXH+fZ0YkZdZi2DsLRpDXT4fTPc8g
The values for GCP_USERNAME and GCP_PASSWORD are encrypted in base64 based on the key created above. Therefore, you cannot use the usual method to decrypt these values.
To encrypt a value to base64, use the following command:
echo "password_value" | gcloud kms encrypt \
--location "global" \
--keyring "key-ring-name" \
--key "key-name" \
--plaintext-file - \
--ciphertext-file - | base64
After obtaining the value, replace it in your .env file accordingly.
The result of executing the code will be as follows:
If you have any suggestions or questions about the content of this article, please feel free to leave a comment below!
Comments
Post a Comment