使用 Amazon Linux 2 挂钩配置 Elastic Beanstalk 以通过 SSH 访问私有 git 存储库

Posted

技术标签:

【中文标题】使用 Amazon Linux 2 挂钩配置 Elastic Beanstalk 以通过 SSH 访问私有 git 存储库【英文标题】:Configuring Elastic Beanstalk for SSH access to private git repo using Amazon Linux 2 hooks 【发布时间】:2021-11-30 05:14:58 【问题描述】:

假设我们在私有存储库中有一个名为shared_package 的自定义 Python 包,托管在 github 或 bitbucket 上。我们的私有存储库配置为通过 SSH 进行只读访问,如所述,例如here for github 和 here for bitbucket。

我们的另一个项目,恰当地命名为dependent_project,依赖于这个shared_package,并且需要部署到AWS Elastic Beanstalk (EB)。我们的环境使用最新的“Python on Amazon Linux 2”平台,我们使用pipenv 作为包管理器。

由于各种原因,我们直接从我们的在线 git 存储库安装shared_package 是最方便的,如here for pipenv 和here for pip 所述。 我们的dependent_projectPipfile 如下所示:

[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
shared_package = git = "ssh://bitbucket.org/our_username/shared_package.git", editable = true, ref = "2021.0"

[dev-packages]
awsebcli = "*"

[requires]
python_version = "3.8"

这在我们的本地开发系统上运行良好,但在将 dependent_project 部署到 Elastic Beanstalk 时,pipenv 安装失败并显示:Permission denied (publickey)

这就引出了一个问题:

如何使用 Amazon Linux 2 platform hooks 配置 Elastic Beanstalk 环境,以便 pipenv 可以通过 SSH 从私人在线 git 存储库成功安装包?

在以下讨论中可以找到一些难题,但这些不使用 Amazon Linux 2 平台挂钩:

Setting up private Github access with AWS Elastic Beanstalk and Ruby container Setting up SSH keys for github private repo access on Elastic Beanstalk What is the recommended way to handle node.js private module dependencies? BitBucket: Host key verification failed Grant S3 access to Elastic Beanstalk instances

【问题讨论】:

【参考方案1】:

总结

假设我们定义了以下 Elastic Beanstalk 环境属性,并且 bitbucket 公钥文件和我们的私钥文件都已上传到指定的 S3 存储桶:

S3_BUCKET_NAME="my_bucket"
REPO_HOST_NAME="bitbucket.org"
REPO_HOST_PUBLIC_KEY_NAME="bitbucket_public_key"
REPO_PRIVATE_KEY_NAME="my_private_key"

然后可以使用.platform/hooks/prebuild中的这个钩子来完成配置:

#!/bin/bash

# git is required to install our python packages directly from bitbucket
yum -y install git

# file paths (platform hooks are executed as root)
SSH_KNOWN_HOSTS_FILE="/root/.ssh/known_hosts"
SSH_CONFIG_FILE="/root/.ssh/config"
PRIVATE_KEY_FILE="/root/.ssh/$REPO_PRIVATE_KEY_NAME"

# remove any existing (stale) keys for our host from the known_hosts file
[ -f $SSH_KNOWN_HOSTS_FILE ] && ssh-keygen -R $REPO_HOST_NAME

# read the (fresh) host key from S3 file and append to known_hosts file
aws s3 cp "s3://$S3_BUCKET_NAME/$REPO_HOST_PUBLIC_KEY_NAME" - >> $SSH_KNOWN_HOSTS_FILE

# copy our private key from S3 to our instance
aws s3 cp "s3://$S3_BUCKET_NAME/$REPO_PRIVATE_KEY_NAME" $PRIVATE_KEY_FILE

# create an ssh config file to point to the private key file
tee $SSH_CONFIG_FILE <<HERE
Host $REPO_HOST_NAME
    User git
    Hostname $REPO_HOST_NAME
    IdentityFile $PRIVATE_KEY_FILE
HERE

# file permissions must be restricted
chmod 600 $SSH_CONFIG_FILE
chmod 600 $PRIVATE_KEY_FILE

注意此文件需要执行权限 (chmod +x &lt;file path&gt;)。

详解

继续阅读以了解详细的理由。

Git

要访问 git 存储库,我们的 Elastic Beanstalk 环境需要安装 git。 这可以使用yum 在平台挂钩中完成(-y 对每个问题都假定“是”):

yum -y install git

SSH 密钥

在我们的 Elastic Beanstalk (EB) 实例和例如 Elastic Beanstalk (EB) 实例之间建立 SSH 连接。一个 bitbucket 存储库,我们需要三个 SSH 密钥:

bitbucket.org 的 public 密钥,用于验证我们是否连接到受信任的主机。

要获取bitbucket.org 的公钥,格式适合known_hosts,我们可以使用ssh-keyscan。 为了安全起见,我们should verify this key 使用“可信”来源。 在我们的例子中,我们能做的最好的就是将公钥指纹与bitbucket(或github)网站上发布的“官方”指纹进行比较。 指纹可以使用ssh-keygen从公钥计算出来,例如

ssh-keyscan -t rsa bitbucket.org | ssh-keygen -lf -

我们存储库的私有密钥和公共密钥。

可以使用ssh-keygen 生成由私钥和公钥组成的密钥对。 私钥必须保密,公钥必须复制到 bitbucket 存储库的“访问密钥”列表中,如bitbucket docs 中所述。 请注意,创建密钥对没有密码是最方便的,否则我们的脚本也需要处理密码。

在 AWS 上存储密钥

在部署期间,公共 bitbucket 主机密钥和我们的私有 repo 密钥需要在 EB 环境中可用。 private 密钥是秘密的,因此它不应存储在源代码中,也不应以其他方式进行版本控制。

最方便的选择是将键值存储为EB environment properties(即环境变量),因为这些在部署期间很容易获得。 原则上,这可以完成,例如使用base64 编码将多行私钥存储在单行环境属性中。 但是,所有 EB 环境属性键和值组合的总大小为limited to a mere 4096 bytes,这基本上排除了此选项。

另一种方法是将密钥文件存储在 AWS S3 上的安全私有存储桶中。 documentation 描述了如何设置一个 IAM 角色来授予对 EC2 实例的 S3 存储桶的访问权限。文档确实提供了一个配置示例,但这使用了.ebextensions,不适用于.platform 钩子。

简而言之,我们可以使用默认设置(启用“阻止公共访问”,无自定义权限)创建一个基本的 S3 存储桶,并将 SSH 密钥文件上传到该存储桶。 然后,使用 AWS IAM Web 控制台,选择 aws-elasticbeanstalk-ec2-role(或者,最好创建一个自定义角色),并附加 AmazonS3ReadOnlyAccess 策略。

在部署到 Elastic Beanstalk 期间,我们可以使用 .platform 挂钩将密钥文件从 S3 存储桶下载到使用 aws cli 的 EC2 实例。

要测试 EC2 和 S3 之间的连接,我们可以使用 eb ssh 连接到 EC2 实例,然后使用例如 aws s3 ls s3://&lt;bucket name&gt; 来列出存储桶内容。

更新 known_hosts

要表明 bitbucket.org 是受信任的主机,需要将其公钥添加到我们实例上的 known_hosts 文件中。 在我们的平台挂钩脚本中,我们删除主机的任何现有公钥,以防它们过时,并用我们在 S3 上的文件中的当前密钥替换它们:

SSH_KNOWN_HOSTS_FILE="/root/.ssh/known_hosts"
[ -f $SSH_KNOWN_HOSTS_FILE ] && ssh-keygen -R $REPO_HOST_NAME
aws s3 cp "s3://$S3_BUCKET_NAME/$REPO_HOST_PUBLIC_KEY_NAME" - >> $SSH_KNOWN_HOSTS_FILE

指定私钥

可以从S3下载私钥如下,我们需要限制文件权限:

PRIVATE_KEY_FILE="/root/.ssh/$REPO_PRIVATE_KEY_NAME"
aws s3 cp "s3://$S3_BUCKET_NAME/$REPO_PRIVATE_KEY_NAME" $PRIVATE_KEY_FILE
chmod 600 $PRIVATE_KEY_FILE

还需要一个 SSH 配置文件来指向私钥:

tee $SSH_CONFIG_FILE <<HERE
Host $REPO_HOST_NAME
    User git
    Hostname $REPO_HOST_NAME
    IdentityFile $PRIVATE_KEY_FILE
HERE
chmod 600 $SSH_CONFIG_FILE

再次,文件permissions must be restricted。

最终脚本显示在顶部的摘要中。 该脚本可以存储,例如在项目文件夹中作为.platform/hooks/prebuild/01_configure_bitbucket_ssh.sh

钩子和配置钩子

请注意,Amazon Linux 2 使用 .platform/hooks 进行正常部署,使用 .platform/confighooks 进行配置部署。 通常,在这两种情况下都需要使用相同的脚本。 为防止代码重复,我们的.platform/confighooks/prebuild/01_configure_bitbucket_ssh.sh 可能如下所示:

#!/bin/bash
source "/var/app/current/.platform/hooks/prebuild/01_configure_bitbucket_ssh.sh"

请注意,应用程序代码在实例上以/var/app/current 结尾。

【讨论】:

以上是关于使用 Amazon Linux 2 挂钩配置 Elastic Beanstalk 以通过 SSH 访问私有 git 存储库的主要内容,如果未能解决你的问题,请参考以下文章

linux系统如何配置yum?

amazon aws ec云Linux ami上安装配置Nginx+PHP+MySQL环境

使用 Packer 在 Amazon EC2 Linux 2 AMI 上安装 Jenkins 和 JDK 11 失败

如何在 Amazon Linux 2 平台上使用 Elastic Beanstalk 部署的 Node Js 中实现 gzip 压缩?

Amazon Linux 系统安装配置zookeeper集群

Linux下安装配置SNMP服务