亚马逊AWS官方博客
在 AWS Nitro Enclaves 中运行 CloudHSM 应用
背景
AWS CloudHSM 是亚马逊网络服务(AWS)提供的一项服务,旨在为客户提供安全的硬件安全模块(HSM)来保护和管理加密密钥。它将传统的硬件安全模块功能与云计算的灵活性相结合,使客户能够在 AWS 云环境中创建和管理自己的加密密钥。AWS CloudHSM 使用符合标准、单租户且经过 FIPS 140-2 三级验证的通用型 HSM 可以为需要符合企业安全标准的企业可以使用 AWS CloudHSM 来管理保护高度机密数据的私钥。此外,CloudHSM 提供了多种访问方式,我们除了可以通过 CloudHSM 的命令行操作 CloudHSM,还可以在程序应用中使用 CloudHSM 支持的标准 API,包括 PKCS#11 和 JCA/JCE(Java Cryptography Architecture/Java Cryptography Extensions)等对 CloudHSM 进行访问。
AWS Nitro Enclaves 是 Amazon Web Services(AWS)提供的一项服务,旨在提供安全且高度隔离的计算环境,用于处理敏感数据和执行安全计算任务。它使用的 AWS Nitro System 技术,可以通过硬件隔离技术将计算实例内的部分资源保护在一个受信任的硬件隔离区域中。Nitro Enclaves 采用 Nitro Hypervisor 技术,在 EC2 实例内部,允许您创建一个 CPU 和内存隔离的计算环境。它没有持久存储、交互式访问或外部网络,仅支持与其父实例通过 vsock 的方式进行安全通信。用户无法通过 SSH 进入 enclave,并且父主机实例的进程、应用程序或用户无法访问 enclave 内的数据和应用程序。
在某些需要使用 CloudHSM 的合规场景下,如果只是单单在 EC2 示例中运行- CloudHSM 应用,在主机被攻陷的情况下,有可能造成 CloudHSM 中密钥被窃取,或者加解密,身份验证、授权等被利用。针对这种情况,我们可以通过将 CloudHSM 应用运行在 Nitro Enclaves 隔离环境中,来进一步增强数据的安全性和完整性。
本篇博客主要介绍了如何在 Nitro Enclaves 环境中运行 CloudHSM 的客户端应用,通过构建,部署两个 demo 应用程序 cloudhsm-enclave和cloudhsm-host 来阐述整个过程。应用程序代码范例可从 github 获取。
- cloudhsm-enclave:运行在 enclave 中的集成了 JCE provider SDK 的 CloudHSM 应用,代码范例中展示了如何在 CloudHSM 集群中生成 AES key
- cloudhsm-host:运行在 EC2 主机实例上,作为访问 enclave 中运行的 CloudHSM 应用的客户端,向 cloudhsm-enclave 发起创建 AES key 的请求
方案概述
下图展示了 CloudHSM 应用的整体方案架构,cloudhsm-host 应用作为请求发起的客户端,运行在 EC2 主机实例中,通过 vsock 与运行在 enclave 中的 cloudhsm-enclave 应用进行通信。cloudhsm-enclave 应用通过运行在 enclave 中的 socat proxy 和运行在 EC2 主机实例上的 vsock proxy 来进行外部访问,当 cloudhsm-enclave 收到 cloudhsm-host 发出的请求时,cloudhsm-enclave 会访问 Secrets Manager 来获取 CloudHSM 集群的 Crypto User 类型的用户的密钥,通过密钥连接到 CloudHSM 实例来实现对 CloudHSM 集群的访问。
本方案的整体的工作流程主要分为下面四个步骤,后面会详细介绍每个步骤:
Step 1:创建并配置 CloudHSM 集群
Step 2:管理 CloudHSM 集群的用户访问
Step 3:构建、部署 cloudhsm-enclave 应用到 Enclave 环境
Step 4:运行 cloudhsm-host 验证 cloudhsm-enclave 应用
前提准备
在开始之前,我们需要做好以下准备工作:
- AWS Account
- VPC:用来在其中管理 EC2 主机和 CloudHSM 集群,选择的 region 为 ap-southeast-1
- 一个启用了 Nitro Enclaves 的 EC2,这个 EC2 工作环境主要用来管理 CloudHSM 集群和构建,部署我们的范例应用。其中需要预先配置好一些基本的工具,如 git,docker 工具等;并需要配置好 java 开发环境,包括 java 1.8.0 运行时,Maven>=3.8.8 等;另外,demo 对于实例的配置需要 vCPU>=4 和 Memory>=8GiB,OS 为 Amazon Linux2
详细步骤
Step 1:创建并配置 CloudHSM 集群
首先,我们通过控制台来创建 CloudHSM 集群;在 CloudHSM 的控制台界面,点击右上角的 Create Cluster 进入 Cluster configuration 界面,进行集群的配置界面,选择合适的 VPC 和 Availability Zone(s)来配置集群。然后跟随引导页面来完成集群的创建。这里需要指出的时,VPC 和 Subnets 只能在创建 CloudHSM 集群的时候指定而不能在创建以后进行更改。
在创建完集群以后,集群进入 Uninitilized 的状态,如下图所示。另外,注意下 CloudHSM 集群的 security group,此时,我们需要把这个 Security Group 添加到 EC2 的安全组中,以允许 EC2 实例对 CloudHSM 集群的网络访问。
接下来,我们需要对集群进行 initialize 操作来创建 CloudHSM 实例并完成集群的初始化。点击上图右上角的 Initialize 按钮,进入 Create an HSM in the cluster 页面,选择 HSM 实例所在的 subnet 后,点击 Create 按钮。此时,CloudHSM 集群开始创建第一个 HSM 实例,实例的创建需要一定的时间。
在 HSM 实例创建完成后,向导会引导我们进入下一个页面 Download certificate signing request,下载 Cluster CSR 并进行签名。
Cluster CSR 签名需要生成 Cluster certificate 和 Issuing certificate,整个过程如下,也可以参考官方文档 Initialize the cluster。
1. 创建私有密钥,根据提示输入密码来生成 key
2. 使用私有密钥创建自签名证书,根据交互提示来完成自签名证书的创建
3. 对集群 CSR 进行签名,注意替换 cluster-teeultuftgy 为您自己的 CloudHSM集群 ID
此时,我们就生成了自签名所需要的 Cluster certificate cluster-teeultuftgy_CustomerHsmCertificate.crt 和 Issuing certificate customerCA.crt。点击上一图中的 Next 进入 Upload certificates 页面,上传我们刚刚生成的 Cluster certificate cluster-teeultuftgy _CustomerHsmCertificate.crt 和 Issuing certificate customerCA.crt。
点击 Upload and Initialize 来启动初始化 CloudHSM 集群。完成初始化后的页面如下,可以看到我们的第一个 IP 为 10.0.10.103 的 HSM 实例已经创建出来了。
在集群初始化完成以后,我们还需要通过 cloudhsm 的命令行来设置管理员账号密码来完成集群的激活。
具体步骤如下:
1. 在 EC2 实例上,安装 CloudHSM 客户端和命令行工具,下面为基于 x86_64 架构的 Amazon Linux 2 的命令行,其他类型的实例请参考 Install CloudHSM CLI
2. 将 Cluster CSR 签名过程中生成的 crt 复制到/opt/cloudhsm/etc/customerCA.crt
3. 配置 CloudHSM CLI,注意替换为您自己 HSM 实例的 IP
4. 激活集群
4.1 进入 cloudhsm-cli 命令交互程序
4.2 运行集群激活命令并根据提示输入密码
4.3 正确输入密码后会出现集群激活的输出,如下图所示,表示集群成功激活
Step 2:配置 CloudHSM 集群的用户访问
CloudHSM 的用户类别分为 Unactivated admin,Admin,Crypto user(CU)和Applicance user(AU)四种类型。在 CloudHSM 集群激活完成后,集群只提供了用来管理用户的管理员用户和 APPLICCANCE_USER 的用户。如果要对 key 进行管理,需要创建 Crypto user 来实现,创建 Crypto user 的步骤如下:
1. 进入 cloudhsm cli 交互控制台
2. 使用 admin 用户登陆来管理用户
3. 创建 role 为 crypto-user 的用户 qyzhangaws,您可以替换下面的 username qyzhangaws 为您自己要指定的用户名
在输入密码后,看到如下的输出表示 crypto-user 类型的用户 qyzhangaws 已经创建成功。
如果此时我们使用 user list 命令来查看的话,会看到类似下图的用户列表,可以在列表中看到新创建的 role 为 crypo-user 的用户 qyzhangaws。
在创建好 Crypto user 用户以后,我们需要将 Crypto user 的密钥提供给 CloudHSM 的应用,从而实现程序对 CloudHSM 集群的访问,这里我们采用了 Secrets Manager 来存储 Crypto user 的密钥,而程序会在运行过程中从 Secrets Manager 获取密钥,进而就可以访问 CloudHSM 集群。
下面我们来将 CloudHSM 的 Crypto User qyzhangaws 导入到 Secrets Manager 中。
在 Secrets Manager 控制台,点击右上角的 Store a new Secret,进入下图 Choose secret type 页面,选择 Other type of secret,在 Key/Value pairs 部分,分别输入 key 为 HSM_USER 和 HSM_PASSWORD 的 CloudHSM 集群的用户 qyzhangaws 和其对应的密码。
点击 Next 按钮,进入 Configure secret 页面,简便起见,我们以 cloudhsm 的集群 ID cloudhsm/cluster-teeultuftgy 来定义 Secret name。
随后,直接根据向导点击 Next 进入 Step 3 Configure rotation,直接继续点击 Next,进入 Step 4 Review,在 Review 页面,点击右下角的 Store 完成 CloudHSM 集群用户密钥的导入。
对于 cloudhsm-enclave,它获取到保存在 Secrets Manager 中的密钥是通过附加在 EC2 实例主机的 IAM Role 的权限,因此,我们还需要给 EC2 的 IAM Role 添加访问 Secrets Manager 的权限。我们可以为 EC2 创建具有如下 IAM policy 权限的 role,或者为当前 Role 的 policy 添加如下的 Policy,来赋予运行在 EC2 实例中的应用访问 Secrets Manger 的权限。
Step 3:部署 cloudhsm-enclave 应用到 Nitro Enclaves 环境
部署应用的整个过程,由准备工具,编译程序,生成 docker 镜像,生成 enclave 镜像和部署 enclave 镜像组成。下面进行详细介绍:
1. 运行以下命令来完成 Nitro CLI 的安装(当前用户为 ec2-user)或参考官方文档 Installing the Nitro Enclaves CLI on Linux
2. 调整 enclave allocator 的配置并重启服务使其生效
3. 为 vsock-proxy 服务添加允许列表。默认情况下,vsock-proxy 只允许转发 kms 的服务访问,所以我们需要对 vsock-proxy 进行配置以允许 vsock-proxy 来转发请求到 Secrets Manager 和 CloudHSM 集群。运行下面的命令,将 Secrets Manager 的 endpoint 和 CloudHSM 集群内 HSM 实例 ip 添加到 vsock-proxy 的允许列表。
4. 运行下面的命令在后台来启动 vsock-proxy 来代理 Secrets Manager 和 CloudHSM 的访问:
5. 构建,编译应用程序 cloudhsm-enclave
首先,从 github 获取应用范例程序
在获取到程序代码后,我们需要对程序代码进行一些配置调整来实现 demo 的运行。
将 Step 1 中保存的 customerCA.crt 来替换掉我们在 examples/cloudhsm/cloudhsm-enclave 下的 customerCA.crt,这个会在我们 bootstrap cloudhsm 的时候用到。
运行以下命令在我们的 EC2 主机实例上安装 CloudHSM JCE provider,对于其他实例类型或 OS 的 EC2,可参考官方文档 Installing the JCE provider 来安装。
将 examples/cloudhsm/cloudhsm-enclave/src/main/java/com/github/qyzhangaws/cloudhsm/handler/CloudHSMHandler.java 中下面的代码替换为您自己的 Secrets Manager 的 Secret 和其所在的 Region。
回到 nitro-enclaves-cloudhsm 目录下,运行下面的命令来编译 cloudhsm-enclave 和 cloudhsm-host 应用:
6. 创建 docker 镜像,Dockerfile 路径为 examples/cloudhsm/cloudhsm-enclave/Dockerfile,内容如下:
从 Dokerfile 中,我们可以看到最终的运行是 run_sample.sh,下面是 run_sample.sh 文件的内容。在上文中,我们提到过,需要在 enclave 中启动 socat proxy 来转发对于外部 Secrets Manager endpoint 和 CloudHSM 集群 HSM 实例的访问。启动 socat proxy 的命令就是在 run_sample.sh 中调用的。
运行下面的命令来创建 docker 镜像,注意替换 HSM_IP 为您自己集群的 HSM 实例 IP。
7. 运行下面的命令来创建 cloudhsm-host 的 enclave 镜像
运行后的输出类似下面的的结果表示镜像生成成功
8. 部署 cloudhsm-enclave 镜像
此时,你会在命令行看到类似下面的输出,表示 enclave 已经创建了一个 EnclaveCID 为 5 的 enclave。
我们刚刚部署的 cloudhsm-enclave 是运行在 debug 模式下,运行下面的命令来获取 enclave 内应用的日志:
你会看到类似下面的日志,表示我们的进程已经正常启动:
需要指出的是,在这里我们只展示了一个 HSM 实例的配置和部署, 在实际的生产环境中,请注意启用多 AZ 的 HSM 实例来保证 CloudHSM 集群的高可用性,当 CloudHSM 集群中有多个 HSM 实例时,需要对 vsock-proxy,Dockerfile 和 run_sample.sh 进行调整来确保 enclave 可以访问到 CloudHSM 集群的所有 HSM 实例。
Step 4:运行 cloudhsm-host 来验证 cloudhsm-enclave 应用
Cloudhsm-host 已经在 Step 3 中编译 cloudhsm-enclave 时完成编译。我们可以运行以下命令运行 cloudhsm-host 向 cloudhsm-enclave 发起生成一个 label 为 nitro-enclave-1 的 AES key:
在执行完成后,控制台会有下面的输出,表示 key 已经创建成功。
我们还可以在 EC2 主机实例上通过 cloudhsm CLI 进入交互模式来验证刚刚生成的 AES key。运行以下命令:
从下面的输出中,我们可以看到刚创建的 label 为 nitro-enclave-1 的 key:
此外,您也可以修改 examples/cloudhsm/cloudhsm-enclave/src/main/java/com/github/qyzhangaws/cloudhsm/handler/CloudHSMHandler.java 中的如下命令行,来改变 label 的值请求生成不同 label 的 key 进行多次验证。
总结
在本篇博客中,我们详细介绍了如何开发,部署在 Nitro Enclaves 环境中运行的 CloudHSM 应用。我们采用了 Secrets Manager 来管理 CloudHSM 集群用户的密钥,并且密钥在 CloudHSM 应用中直接获取,一定程度减少了被窃取的可能性。CloudHSM 代码实例实现了如何生成基于 AES 算法的密钥,您可以基于此代码实例来您可以基于此代码实例来对直接运行在 EC2 实例的 CloudHSM 应用进行迁移,也可以基于此实现更多的 CloudHSM 应用的功能,进一步提升 CloudHSM 应用的安全性。