Использование KMS для доставки секретов в функцию
Часто нужно передать в функцию какой-то секрет. Например, ключ доступа в стороннее 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.
{
"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
Полный код примера тут.