Перейти к основному содержимому

Использование KMS для доставки секретов в функцию

· 3 мин. чтения

Часто нужно передать в функцию какой-то секрет. Например, ключ доступа в стороннее API. Его можно передать через переменные окружения, но в таком случае он будет храниться в открытом виде.

Если мы хотим ограничить доступ к этой информации, только теми, кто будет иметь достаточные права, нам пригодится KMS — key management service.

KMS обеспечивает создание, надежное хранение и работу с ключами шифрования. Мы можем создать ключ шифрования, выдать права на его использование сервисному аккаунту. После этого от лица этого аккаунта мы сможем вызывать методы encryptи decrypt. Они подойдут для того чтобы зашифровать небольшой секрет. Для шифрования большого объема данных лучше воспользоваться схемой envelope encryption, когда создается дополнительный ключ, файл шифруется им, а он в свою очередь шифруется при помощи KMS. Но это выходит за рамки текущего примера.

И так, подготовим наш секрет. Для наглядности в качестве секрета и для простоты валидации возьмем обычную фразу и запишем ее в файл _plaintext.txt_.

echo 'The quick brown fox jumps over the lazy dog' > plaintext.txt

Теперь создадим ключ в KMS при помощи yc CLI.

yc kms symmetric-key create \
--name kms-demo \
--default-algorithm aes-256 \
--rotation-period 24h

При помощи yc и только что созданного ключа мы можем зашифровать наш plaintext.txt. Зашифрованный текст положим в файл ciphertext.txt

yc kms symmetric-crypto encrypt \
--name kms-demo \
--plaintext-file plaintext.txt \
--ciphertext-file ciphertext.txt

Теперь запишем id ключа и шифротекст в файл .env, чтобы использовать в serverless.

yc kms symmetric-key get --name=kms-demo --format=json | jq -r '"KEY_ID=\(.id)"' > .envecho "CIPHERTEXT=$(base64 -i ciphertext.txt)" >> .env

В том случае, если размер ваших секретов превышает 4kb, передать их через переменные окружения не получится. Но это не беда. Шифротекст можно спокойно включить в исходный код. В таком случае вы сможете использовать секреты размером до 32kb. Теоретически можно и больше, но тогда в KMS будет храниться только ключ, а расшифровка будет производиться не через вызов метода Decode, а локально средствами выбранного языка программирования.

Ниже package.json и код функции на Node.js.

package.json
{
"name": "kms-demo",
"version": "1.0.0",
"type": "module",
"dependencies": {
"@yandex-cloud/nodejs-sdk": "latest"
}
}
import { Session, cloudApi, serviceClients } from '@yandex-cloud/nodejs-sdk';

const { kms: { symmetric_crypto_service: { SymmetricDecryptRequest } } } = cloudApi;

const {CIPHERTEXT, KEY_ID} = process.env;
const session = new Session();
const client = session.client(serviceClients.SymmetricCryptoServiceClient);

const result = client.decrypt(
SymmetricDecryptRequest.fromPartial({
keyId: KEY_ID,
ciphertext: Buffer.from(CIPHERTEXT, 'base64')
})
);

export const handler = async function () {
const secret = await result;
return {
statusCode: 200,
body: Buffer.from(secret.plaintext).toString()
};
};

Раздеплоим функцию при помощи serverless CLI.

sls deploy

Теперь можно проверить

sls invoke -f env-demo

И в консоли мы увидим следующее:

Serverless: {"statusCode":200,"body":"The quick brown fox jumps over the lazy dog

Полный код примера тут.