总结
假设我们定义了以下 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 <file path>)。
详解
继续阅读以了解详细的理由。
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://<bucket name> 来列出存储桶内容。
更新 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 结尾。