В работе бессерверных приложений, которые еще ассоциируют с «лямбдами» или «функциями», часто требуется аутентификация на сервисе или в API вышестоящего уровня. При этом могут использоваться учетные данные, передаваемые в БД, или API-ключ, если требуется запрос во внешнюю систему.

Зачастую возникает вопрос: «Как надежно и безопасно внедрять секреты в бессерверные приложения?»

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

Мы расскажем о пяти стратегиях управления секретами в бессерверных приложениях в порядке снижения степени защищенности.

1. Использование IAM-решений

Большинство облачных провайдеров и многие решения on-premise предлагают свои надежные средства управления идентификацией и доступом (IAM). Благодаря этим средствам бессерверное приложение сможет получить доступ к другим ресурсам, не обмениваясь с ними учетными данными. Подобные решения могут поддерживать взаимодействие между несколькими поставщиками услуг.

Предположим, что облачной функции Google Cloud необходим доступ к данным, хранящимся в частном бакете AWS S3. Обычно в таком случае создается пара ключей доступа к AWS, которая внедряется в облачную функцию. Однако вместо этого в AWS можно создать поставщика OpenID Connect (OIDC), и тогда Amazon будет считать Google своим доверенным поставщиком аутентификационных данных. Затем нужно предоставить облачной функции разрешение на доступ к данным в частном бакете S3. При этом вам не придется формировать пары ключей доступа или вводить учетные данные, поскольку бессерверное приложение будет проходить аутентификацию и авторизацию с помощью собственного удостоверения.

К сожалению, использование IAM для управления секретами возможно далеко не всегда. Не все сервисы поддерживают IAM и еще меньше сервисов поддерживают IAM между разными поставщиками услуг. В таких случаях придется вводить учетные данные напрямую.

2. Использование менеджера секретов

Многие поставщики услуг предлагают собственные решения для управления секретами на своей платформе, например, AWS Secrets Manager или Azure Key Vault. Такого рода решения позволяют безопасно хранить и извлекать произвольные значения, при этом аутентификацию и авторизацию обеспечивает IAM-решение самого поставщика. 

В случае бессерверных приложений секреты могут передаваться через API менеджера секретов либо жестко привязываться в момент развертывания.

Если ваш поставщик услуг не предлагает собственного решения для управления секретами, вы можете использовать внешний менеджер секретов, например, HashiCorp Vault или CyberArk Conjur. Подобные сервисы требуют обеспечения непрерывной работы, постоянной поддержки, применения обновлений и исправлений — вряд ли внешние менеджеры можно считать оптимальными, если набор ваших бессерверных приложений не очень велик. Такие инструменты больше подходят для развертывания в мультиоблачных и гибридных облаках и зачастую предлагают более богатую функциональность, чем менеджеры секретов от поставщиков услуг.

Менеджеры секретов предлагают и другие преимущества, например, централизованный доступ, ведение журнала аудита — всё это позволяет глубже разобраться, как именно используются секреты в вашей среде. Иногда менеджеры секретов неприменимы из-за отсутствия юридического согласия или наличия экспортных ограничений — в этом случае пригодятся альтернативы, перечисленные ниже.

3. Использование объектных хранилищ

Лучше всего иметь надежное выделенное решение для управления секретами, но существуют и более экономичные альтернативы со сниженным порогом входа, например, хранилища объектов. Они особенно актуальны для сред разработки и промежуточного развертывания (staging) с менее строгими требованиями к безопасности. Google Cloud StorageAWS S3Azure Blob Storage и другие крупные поставщики услуг предлагают собственные хранилища объектов, которые позволяют хранить большие двоичные BLOB-объекты в рамках особой виртуальной архитектуры, напоминающей файловую систему.

Вы можете хранить секреты в виде объектов в хранилище и загружать их в свое бессерверное приложение в ходе упаковки, развертывания или начальной загрузки.

Хранилище объектов годится для размещения секретов бессерверных приложений только в том случае, если правильно настроены доступы к IAM. Вы также можете разрешить аудит и логирование для большинства объектных хранилищ и получить представление о том, как используются секреты в вашей организации.

Если же вы не сумеете должным образом защитить объектное хранилище, то оно рискует стать мишенью для атак.

В зависимости от требований к безопасности, вы можете зашифровать данные с помощью специального ключа, а потом записать их в хранилище объектов.  Это так называемые ключи шифрования, управляемые клиентами (CMEK). Такая функциональность включена в API далеко не у всех поставщиков, иногда ее нужно реализовывать самостоятельно.

Самым большим недостатком объектного хранилища является модель доступов: по-настоящему надежно защитить хранилище объектов — нетривиальная задача. Второй недостаток заключается в том, что при крупномасштабных развертываниях такой подход может оказаться весьма затратным. Помимо фиксированной ежемесячной стоимости хранилища придется платить за полосу пропускания при доступе к секретам.

4. Использование зашифрованных переменных окружения

Если вы готовы отказаться от централизованного аудита, логирования и управления, чтобы снизить уровень затрат и сложность решения, воспользуйтесь зашифрованными переменными окружения. Перед тем как разворачивать бессерверное приложение, зашифруйте все свои секреты с помощью ключа шифрования или службы управления ключами (КМS).

Когда секреты будут зашифрованы, добавьте в бессерверное приложение код для считывания зашифрованного секрета из переменной окружения, его последующей расшифровки и сохранения текстового ответа в памяти. При использовании KMS вашему бессерверному приложению потребуется специальный доступ для расшифровки, который обычно выдает IAM-система.

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

5. Использование переменных окружения в виде открытого текста

Несмотря на подкупающую простоту, хранить секреты в переменных окружения в виде простого текста небезопасно. Любой процесс, библиотека или зависимость, запущенные внутри процесса, имеют доступ к операционному окружению, и это создает уязвимости, которые эксплуатируют многие актуальные угрозы. Вредоносная зависимость может с большой легкостью получить доступ к среде исполнения процессов и отправить чувствительную информацию в системы, находящиеся под контролем хакеров.

Помимо этого, большая часть бессерверных фреймворков не считает переменные окружения безопасными для себя. Любой пользователь, обладающий доступом на чтение или просмотр в бессерверном приложении, может легко получить доступ к его переменным окружения из веб-консоли или через вызов API.

Нельзя хранить секретную или конфиденциальную информацию в переменных окружения в незашифрованном виде.

Эволюция, а не революция

Управление секретами для бессерверных приложений развивается очень быстро и динамично, но используемые при этом методы защиты не смогут остановить по-настоящему дерзкого злоумышленника. Хакеры хорошо знают управление секретами и используют его как один из методов атак на системы. Чтобы обеспечить максимальную безопасность, авторы бессерверных приложений должны тщательно проверять и защищать свои деревья зависимостей по принципам наименьших привилегий и нулевого доверия.

Никогда не прекращайте учиться!

Если вам интересна экосистема Serverless-сервисов и все, что с этим связано, заходите в наше сообщество в Telegram, где можно обсудить serverless в целом. Один из членов нашего комьюнити выкатил библиотеку на python для работы с  Yandex Lockbox . Lockbox — cервис для создания и хранения секретов в инфраструктуре Yandex.Cloud, можно создавать секреты в консоли управления или с помощью API. Сервис еще в превью, но сейчас уже можно потестировать и сам сервис и библиотеку.

Комментарии (1)


  1. brnovk
    09.02.2022 14:13
    +1

    На практике, в lambdas (nodejs), пользовал несколько способов:

    1. Encrypted environment variables (с помощью KMS). Encryption context по умолчанию - обьект враппер с 1 полем "LambdaFunctionName" (если шифровать значение ручками из UI). Если использовать кастомный KMS - каждый ключ 1$ в месяц (стандартные AWS Managed - бесплатные кажется).

    const awsSdk = require("aws-sdk");
    const kms = new awsSdk.KMS();
    exports.handler = async (event, context, callback) => {
        let encryptedValue = process.env.SOME;
    		let decryptedValue = await kmsDecrypt(encryptedValue, {
    			LambdaFunctionName: context.functionName
    		}, undefined);
        // ...
    };
    
    async function kmsDecrypt(dataToDecrypt, encryptionContext, keyId) {
        const params = {
            CiphertextBlob: Buffer.from(dataToDecrypt, "base64")
        };
        if (keyId) {
    		    params.KeyId = keyId;
        }
    	if (encryptionContext && isObject(encryptionContext) && Object.keys(encryptionContext)) {
    		params.EncryptionContext = encryptionContext
    	}
        const data = await kms.decrypt(params).promise();
        return data.Plaintext.toString("ascii");
    }


    2. Parameter Store (с WithDecryption). Цена - кажется $0.05 за параметр в месяц.

    const awsSdk = require("aws-sdk");
    const ssm = new (require("aws-sdk/clients/ssm"))();
    exports.handler = async (event, context, callback) => {
    	let value = await getParameterStoreValue("/some/parameter/name");
        // ...
    };
    
    async function getParameterStoreValue(paramName) {
        const parametersResult = await ssm.getParameters({ Names: [paramName], WithDecryption: true }).promise();
        return parametersResult.Parameters[0].Value;
    }


    3. SecretManager - по началу пользовались, но потом отказались (дороговато). $0.40 за секрет в месяц - в 8 раз дороже, чем ParameterStore.