应该如何使用 Amazon Web 服务及其弹性 beantalk 将机密文件推送到 EC2 Ruby on Rails 应用程序?

Posted

技术标签:

【中文标题】应该如何使用 Amazon Web 服务及其弹性 beantalk 将机密文件推送到 EC2 Ruby on Rails 应用程序?【英文标题】:How should secret files be pushed to an EC2 Ruby on Rails application using amazon web services with their elastic beanstalk? 【发布时间】:2012-12-08 11:38:22 【问题描述】:

如何使用 Amazon Web 服务及其弹性 beantalk 将机密文件推送到 EC2 Ruby on Rails 应用程序?

我将文件添加到 git 存储库,然后推送到 github,但我想将我的秘密文件保留在 git 存储库之外。我正在使用以下方式部署到 aws:

git aws.push

以下文件在 .gitignore 中:

/config/database.yml
/config/initializers/omniauth.rb
/config/initializers/secret_token.rb

按照此链接,我尝试将 S3 文件添加到我的部署中: http://docs.amazonwebservices.com/elasticbeanstalk/latest/dg/customize-containers.html

引用该链接:

示例代码段

以下示例从 Amazon S3 存储桶下载一个 zip 文件并将其解压缩到 /etc/myapp:

sources:  
    /etc/myapp: http://s3.amazonaws.com/mybucket/myobject 

按照这些指示,我将文件上传到 S3 存储桶,并将以下内容添加到 .ebextensions 目录中的 private.config 文件中:

sources:
  /var/app/current/: https://s3.amazonaws.com/mybucket/config.tar.gz

该 config.tar.gz 文件将解压到:

/config/database.yml
/config/initializers/omniauth.rb
/config/initializers/secret_token.rb

但是,在部署应用程序时,S3 主机上的 config.tar.gz 文件永远不会被复制或提取。我仍然收到找不到 database.yml 的错误,并且 EC2 日志没有配置文件的记录,这是错误消息:

Error message:
  No such file or directory - /var/app/current/config/database.yml
Exception class:
  Errno::ENOENT
Application root:
  /var/app/current

【问题讨论】:

【参考方案1】:

从那里安全文档 Amazon EC2 支持用于文件加密的 TrueCrypt 和用于传输数据的 SSL。查看这些文件

Security Whitepaper Features Risk and Compliance Best Practices

您可以上传带有加密磁盘的服务器实例,也可以使用私有仓库(我认为这对 github 来说是成本,但还有其他选择)

【讨论】:

嗯,我认为这里最重要的事情之一是确保存在正确的权限,并且从 S3 请求文件的应用程序具有正确的权限,但两者都在我的用户下运行,我有文件的权限,所以我不确定如何判断这是否是问题。【参考方案2】:

我认为您想要做的“正确”方法是使用 IAM 角色。你可以在这里看到一篇关于它的博文:http://aws.typepad.com/aws/aws-iam/

基本上,它允许您启动 EC2 实例,而无需在任何配置文件中放置任何个人凭证。当您启动实例时,它将被分配给定的角色(一组使用 AWS 资源的权限),并且将使用 Amazon IAM 自动在机器上放置一个轮换凭证。

【讨论】:

【参考方案3】:

使用环境变量是一个好方法。在环境中引用密码,所以在一个yaml文件中:

password: <%= ENV['DATABASE_PASSWORD'] %>

然后直接使用 eb 或控制台在实例上设置它们。

您可能担心在环境中容易获得此类敏感信息。如果某个进程破坏了您的系统,无论它在哪里,它都可能获得密码。 Heroku 等许多 PaaS 提供商都使用这种方法。

【讨论】:

【参考方案4】:

为了让.ebextension/*.config 文件能够从 S3 下载文件,它们必须是公开的。鉴于它们包含敏感信息,这是一个坏主意。

您可以启动 Elastic Beanstalk 实例 with an instance role,并且可以授予该角色访问相关文件的权限。不幸的是,.ebextension/*.config 文件的 file:sources: 部分没有使用此角色的直接访问权限。

您应该能够使用AWS SDK for Ruby 的AWS::S3::S3Object 类编写一个简单的脚本来下载文件,并使用command: 而不是sources:。如果不指定凭据,SDK 会自动尝试使用该角色。

您必须为您的角色添加一个策略,允许您专门下载您感兴趣的文件。它看起来像这样:

                       
  "Statement": [
    
    "Effect": "Allow",
     "Action": "s3:GetObject",
     "Resource": "arn:aws:s3:::mybucket/*"
    
  ]

然后你可以在你的 .config 文件中做这样的事情

files:
  /usr/local/bin/downloadScript.rb: http://s3.amazonaws.com/mybucket/downloadScript.rb
commands:
  01-download-config:
    command: ruby /usr/local/downloadScript.rb http://s3.amazonaws.com/mybucket/config.tar.gz /tmp
  02-unzip-config:
    command: tar xvf /tmp/config.tar.gz
    cwd: /var/app/current

【讨论】:

【参考方案5】:

我认为最好的方法是不要破解 AWS(设置挂钩、上传文件)。只需使用 ENV 变量。

使用 gem 'dot-env' 进行开发(即 'config/database.yml' 中的 )和默认 AWS 控制台在 Beanstalk 中设置变量。

【讨论】:

【参考方案6】:

在 S3 中存储敏感文件并自动将它们复制到您的 Beanstalk 实例是可能的(并且很容易)。

当您创建 Beanstalk 应用程序时,会自动创建一个 S3 存储桶。该桶用于存储应用版本、日志、元数据等。

分配给您的 Beanstalk 环境的默认 aws-elasticbeanstalk-ec2-role 具有对该存储桶的读取权限。

因此,您只需将敏感文件放在该存储桶中(在存储桶的根目录或您想要的任何目录结构中),然后创建一个.ebextension 配置文件以将它们复制到您的 EC2 实例.

这是一个例子:

# .ebextensions/sensitive_files.config

Resources:
  AWSEBAutoScalingGroup:
    Metadata:
      AWS::CloudFormation::Authentication:
        S3Auth:
          type: "s3"
          buckets: ["elasticbeanstalk-us-east-1-XXX"] # Replace with your bucket name
          roleName: 
            "Fn::GetOptionSetting": 
              Namespace: "aws:autoscaling:launchconfiguration"
              OptionName: "IamInstanceProfile"
              DefaultValue: "aws-elasticbeanstalk-ec2-role" # This is the default role created for you when creating a new Beanstalk environment. Change it if you are using a custom role

files:
  /etc/pki/tls/certs/server.key: # This is where the file will be copied on the EC2 instances
    mode: "000400" # Apply restrictive permissions to the file
    owner: root # Or nodejs, or whatever suits your needs
    group: root # Or nodejs, or whatever suits your needs
    authentication: "S3Auth"
    source: https://s3-us-west-2.amazonaws.com/elasticbeanstalk-us-east-1-XXX/server.key # URL to the file in S3

这在此处记录:http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/https-storingprivatekeys.html

【讨论】:

【参考方案7】:

我知道这是一篇旧帖子,但我无法在任何地方找到另一个答案,所以我熬夜才想出一个。我希望它可以为您节省几个小时。

我同意开发人员的意见,他们发布了多少 PITA 来强制开发人员将 ENV 变量放入他们的本地 dev database.yml 中。我知道 dotenv gem 很好,但您仍然需要维护 ENV 变量,这会增加启动站所需的时间。

我的方法是在 S3 上由 EB 创建的存储桶中存储一个 database.yml 文件,然后使用 .ebextensions 配置文件在服务器的 pre hook 目录中创建一个脚本,以便在解压缩到暂存后执行目录,但在资产编译之前——当然,没有 database.yml 就会爆炸。

.config 文件是

# .ebextensions/sensitive_files.config
# Create a prehook command to copy database.yml from S3
files:
  "/opt/elasticbeanstalk/hooks/appdeploy/pre/03_copy_database.sh" :
    mode: "000755"
    owner: root
    group: root
    content: |
        #!/bin/bash
        set -xe
        EB_APP_STAGING_DIR=$(/opt/elasticbeanstalk/bin/get-config  container -k app_staging_dir)
        echo EB_APP_STAGING_DIR is  $EB_APP_STAGING_DIR >/tmp/copy.log
        ls -l $EB_APP_STAGING_DIR >>/tmp/copy.log
        aws s3 cp s3://elasticbeanstalk-us-east-1-XXX/database.yml $EB_APP_STAGING_DIR/config/database.yml >>/tmp/copy.log 2>>/tmp/copy.log

注意事项

当然bucket名称中的XXX是EB创建的序列号。您必须检查 S3 才能看到存储桶的名称。 我创建的脚本文件的名称很重要。这些脚本是按字母顺序执行的,所以我很小心地给它命名,所以它排在asset_compilation 脚本之前。 显然将输出重定向到 /tmp/copy.log 是可选的

对我帮助最大的帖子是Customizing ElasticBeanstalk deployment hooks

由 Kenta@AWS 发布。谢谢健太!

【讨论】:

以上是关于应该如何使用 Amazon Web 服务及其弹性 beantalk 将机密文件推送到 EC2 Ruby on Rails 应用程序?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Amazon EC2 管理多个子域?

适用于 iOS 消费的 Web 服务(在 Amazon 上)安全性

用于 Java Web 应用程序的最佳 Amazon 服务器实例

带有 IIS 的 Amazon 弹性负载均衡器

具有弹性 IP 的 Amazon EC2 自动扩展实例

在 Amazon 云上使用 Java Web 服务