DevGang
Авторизоваться

Развертывание Lambda со статическим IP еще никогда не было таким простым

В данном курсе вы узнаете:

  • Как развернуть Lambda со статическим IP (для целей внесения в белый список) 
  • Выполнить операции NodeJS SFTP, используя лямбда-код.

Вашему бессерверному приложению может потребоваться подключение к серверу-партнеру, для которого требуется белый список IP-адресов.

Мы будем использовать Serverless Framework для развертывания нашей функции Lambda и Typescript AWS CDK для создания инфраструктуры, необходимой для предоставления нашей Lambda статического IP-адреса.

Также мы будем использовать пакет NodeJS ssh2-promise для выполнения операций SFTP в нашей функции Lambda.

Вот что мы будем строить:

Создайте функцию Lambda, размещенную в VPC, со статическим IP-адресом.

VPC, шлюз NAT и эластичный IP-адрес

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

const vpc = new Vpc(stack, 'Vpc', {
    vpcName: 'vpc',
    natGateways: 1, // 👈 Automatically creates an Elastic IP
    maxAzs: 1, // 👈 Use more if you need high availability
    subnetConfiguration: [
        {
        name: 'private-subnet-1',
        subnetType: SubnetType.PRIVATE_WITH_NAT,
        cidrMask: 24,
        },
        {
        name: 'public-subnet-1',
        subnetType: SubnetType.PUBLIC,
        cidrMask: 24,
        },
    ],
});
Отказ от ответственностиЭта архитектура будет стоить денег. Шлюз NAT работает на экземпляре EC2, который будет стоить вам около 30 долларов в месяц. Эта цена умножается на количество используемых вами зон доступности.

Мы также рекомендуем вам использовать выходы CloudFormation для хранения идентификаторов ресурсов, которые вам понадобятся позже. Мы хотим пощекотать этот чистый код IaC в нашем PR.


export const vpcSecurityGroupOutputId = 'SgOutputId';
export const vpcPrivateSubnetOutputId = 'VpcPvSubOutputId';
...

const privateSubnets = vpc.selectSubnets(
    { subnetType: SubnetType.PRIVATE_WITH_NAT }
);
export const [privateSubnetId1] = privateSubnets.subnetIds;

// 👇 Outputing the IDs of the resources in case another stack needs them
new CfnOutput(stack, vpcSecurityGroupOutputId, {
    value: vpc.vpcDefaultSecurityGroup,
});
new CfnOutput(stack, vpcPrivateSubnet1OutputId, {
    value: privateSubnetId1,
});

Разверните лямбда-функцию

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

export const staticIpLambda = {
  timeout: 15,
  handler: getHandlerPath(__dirname),
  vpc: {
    securityGroupIds: [ stack.resolve(vpc.vpcDefaultSecurityGroup) ],
    subnetIds: [ stack.resolve(privateSubnetId1) ],
    },
};

Наша функция Lambda развернута в нашей частной подсети.

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

Вы можете получить эластичный IP-адрес своего шлюза NAT с помощью консоли AWS.

Перейдите в сервис VPC и нажмите Elastic IPs. Вы должны увидеть эластичный IP-адрес, созданный CDK.

Теперь просто напишите своему партнеру и попросите его внести этот IP-адрес в белый список.

Выполняйте операции SFTP в своей функции Lambda

Мы рассмотрим очень специфический вариант использования SFTP и проблему, с которой столкнулись при использовании ssh2-promise и плагина serverless-esbuild.

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

Мы хотели бы поделиться с вами этим примером использования, потому что вы можете столкнулся со странными проблемами, когда пакет ssh2-promise неправильно встраивается в код .zip code Lambda.

SSH-ключЕсли вашему партнеру по SFTP требуется ключ SSH, мы рекомендуем вам сохранить ключ в AWS Secrets Manager. Затем вы можете получить его в своей функции Lambda, используя промежуточное ПО Middy Secrets Manager. Он предоставит ключ в виде строки в контексте вашей функции Lambda.

Сохраните файл, который вы хотите отправить, в папке /tmp вашего Lambda.

Пакету ssh2-promise потребуется доступ к файловой системе для отправки вашего файла. Один из способов добиться этого в контексте функции Lambda — использовать папку /tmp.

Эта папка доступна для записи и будет удалена, когда ваша функция Lambda будет завершена.

ПредупреждениеПапка /tmp не является постоянной. Если вы хотите отслеживать файлы, которые вы отправили, вам также следует использовать S3.
Также имейте в виду, что папка /tmp является общей для последовательных вызовов Lambda в одной и той же среде выполнения. Используйте уникальное имя файла, чтобы избежать ошибок.

Вот как выглядит окончательный код с пакетом ssh2-promise:

fs.writeFileSync('/tmp/myFile.txt', 'Hello World!');

const sshPrivateKey = context["SSH_PRIVATE_KEY"]

const ssh = new SSH2Promise({
    host: 'sftpIpAddress',
    username: 'sftpUsername',
    privateKey: sshPrivateKey,
    port: "SFTP_PORT",
});

await ssh.connect();
const sftp = ssh.sftp();


await sftp.fastPut('/tmp/myFile.txt', "distant_name.txt");

await ssh.close();

Ловушка

Если, как и мы, вы используете плагин serverless-esbuild для объединения своей функции Lambda, вы можете столкнуться с некоторыми странными проблемами.

Пакет ssh2-promise неправильно включен в вашу функцию Lambda.

Чтобы решить эту проблему, мы сначала исправили плагин serverless-esbuild, чтобы разрешить исключение объединения модулей yarn3. Мы хотим, чтобы пакет ssh2-promise НЕ был связан с esbuild.

Патч доступен здесь в виде github gist

Затем нам пришлось добавить пакет ssh2-promise в раздел externals нашей конфигурации esbuild.

// serverless.ts

const serverlessConfiguration = {
  ..., // 👈 Your other serverless config
  custom: {
    esbuild: { ...esbuildConfig, external: ['ssh2-promise'] },
  },
};

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

#AWS
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться