# vault-demo **Repository Path**: songlu-cube/vault-demo ## Basic Information - **Project Name**: vault-demo - **Description**: Vault项目调研示例 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-03-15 - **Last Updated**: 2023-03-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Vault配置中心产品调研实施方案 ## 一、需求描述 nacos作为配置中文,数据都是明文方式存储,这无法保证数据的安全性。需要引用新的框架,对项目中的机密配置数据(如API密钥、账号密码等)进行加密存储。 ## 二、技术调研 ### 2.1 Vault概述 Hashicorp Vault是一个密码/证书集中式管理工具,通过HTTP-API对外提供统一的密码访问入口,并且提供权限控制以及详细的日志审计功能,解决了管理机密数据的问题。 Vault提供了对数据库账号密码、外部服务的API秘钥、证书、通信凭证等机密数据的安全存储(key/value)和控制。它能处理key的续租、撤销、审计等功能。通过API访问可以获取到加密保存的密码、ssh key、X.509的certs等。 它的特性包括: - **身份验证**:数据的访问都有严格的访问控制。 - **加密存储**:Vault在数据持久化存储前,对其进行加密存储。 - **Rotate-Key**:如果把Vault当做加密服务来使用的话,可以设置rotate的时间来生成一个新的Key。 - **审计日志**:所有对API的调用都会记录在一个审计日志上 ### 2.2 相关概念 #### 2.2.1 Policies 策略 Vault中所有的定义都是基于路径的,策略也不例外。策略确切地定义了客户端可以访问哪些路径,以及在这些路径下可以执行哪些操作。 让我们看看一个简单的策略是如何定义的: ```Shell path "secret/accounting"{ capabilities = [ "read"] } ``` 这个策略的意思就是,能够读取`secret/accounting`路径下的配置数据。 #### 2.3.2 Secrets Engines 加密引擎 [Secrets Engines](https://developer.hashicorp.com/vault/docs/secrets)是一组提供了存储、生成和加密数据的功能组件,非常灵活好用。 Vault提供了各种加密引擎,如K-V存储、PKI证书、Transit等等。  最常用的还是K-V存储,在Vault上面K-V存储有两个版本: - v1版本:普通存储 - v2版本:带版本控制,可以用来回滚、撤销等操作 #### 2.3.3 Access 认证 要访问Vault中的资源,客户端需要使用一种受支持的方法对自身进行身份认证。  Vault中的身份认证(AuthN)和授权(AuthZ)是完全分开的。Vault用户或者app可以使用某一个启用了的认证方式来进行AuthN,但不管通过什么方式验证了身份之后,最终都会获得一个Token,它只是使用特殊HTTP头在每个API请求上发送的字符串。 > 默认情况下,Token是没有任何关于用户的权限的,一定要绑定了policy才有可能有权限。 Vault还支持其他身份验证机制,如LDAP,JWT,TLS证书等。所有这些机制都建立在基本令牌机制之上:一旦Vault验证了我们的客户端,它将提供一个令牌,然后我们可以使用它来调用其他API接口。 ## 三、使用场景 ### 3.1 存储账号密码的服务器 目前我们有服务器需要访问到有密码的后端的时候,有几种方案: - export到环境变量 - 写死到代码里面 - 上线的时候使用自动化工具对变量进行替换 第一种方案带来的问题是使用麻烦,后两种方案带来的问题是维护和变更麻烦。 比如DB密码泄露,需要修改密码,首先DBA修改密码,然后通知到应用,应用再做代码上的变更。 如果使用Vault的话,DBA只要在Vault上面修改好密码之后,通知应用重新从Vault拉取最新密码就行了。 ### 3.2 为每一个操作单位动态分配账号 比如过去我们想要对某些敏感操作进行审计,但是由于生成账号比较麻烦,所以存在公用账号的情况。 Vault支持为某些后端动态生成账号的功能,比如SQL,当某个应用向Vault请求账号密码的时候,Vault能够为每次请求生成一个独一无二的SQL账号密码。 ### 3.3 作为证书服务器 Vault能够作为CA服务器,根据请求信息自动颁发证书。并且提供在线CA和CRL的功能。 不过目前只能在vault里面新生成ROOT-CA,不能导入原有的ROOT-CA。 ### 3.4 作为OAUTH服务器 Vault支持多种认证后端,比如github、kubernetes、账号密码等等。 Vault能够将这些账号关联成一个用户,在用户认证之后返回一个Token供用户使用。 用户通过Token可以访问限制的资源。 ## 四、演示示例 ### 4.1 启动服务 使用Docker容器启动Vault服务。 ```Shell # 拉去Vault镜像 docker pull vault # 启动镜像 docker run vault:latest ``` ### 4.2 管理员登录 Vault 启动有两种模式,dev和prod。 在dev模式下,提供了Web页面,地址为:http://localhost:8200/ui/。 Root用户的启动密码在日志中会打印出来,我们使用这个Root Token登录系统即可。  ### 4.3 存储数据 在Secrets菜单中,我们可以为各个应用创建存储。比如,创建一个k-v模式的应用存储。  我们选择`KV模式`就好,然后下一步。  输入名称,就完成了。  然后,我们就可以在`demo`的引擎中创建数据存储了。  然后,我们创建两个存储,分别是`demo1`和`demo2`。  ### 4.4 配置策略 然后,我们为`demo`配置一下策略,点击`Policies`菜单。  我们创建访问策略,这个策略下,可以访问`demo1`的数据,无法访问`demo2`的数据。  ### 4.5 配置授权 在Access中,可以使用刚才配置的策略,创建授权,授权有很多种,这里演示`Username&Password`授权模式。  创建好以后,我们创建一个用户。  ### 4.6 访问数据 然后,使用创建的`test`用户登录系统。  登录系统后,根据策略,该用户就看到限定的数据,其他数据无权访问。  ## 五、实施方案 ### 5.1 服务安装 使用Docker下载[Vault镜像](https://hub.docker.com/_/vault/)并启动。 ```sh # 下载镜像 docker pull vault:latest # dev模式启动 docker run --cap-add=IPC_LOCK --name=dev-vault -d vault ``` 命令执行成功后,vault服务已经在dev模式下启动了。 dev模式提供了Web页面,地址为:http://localhost:8200/ui/,root用户的启动密码在日志中会打印出来,我们使用这个Root Token登录系统即可。  如果正常,表示我们的vault已经安装成功了。 ### 5.2 服务启动 在dev模式下,数据都是存储在内存中的,如果容器重启,那么配置的数据都会丢失。所以,我们需要对数据进行持久化存储。 #### 5.2.1 服务启动 在本地的`/Users/lou/docker/vault/config`目录下创建一个`local.json`文件,内容如下: ```sh { "storage": { "file": { "path": "/vault/file" } }, "listener": [ { "tcp": { "address": "0.0.0.0:8200", "tls_disable": true } } ], "default_lease_ttl": "168h", "max_lease_ttl": "720h", "ui": true } ``` 然后,执行启动命令,就可以用上面的配置来启动vault服务了。 ```sh docker run \ --cap-add=IPC_LOCK \ --name=dev-config-vault \ -v /Users/lou/docker/vault/config:/vault/config \ -v /Users/lou/docker/vault/file:/vault/file \ -v /Users/lou/docker/vault/logs:/vault/logs \ -p 8200:8200 \ -d vault server ``` #### 5.2.2 初始化系统 登录`http://localhost:8200/`页面,第一次需要初始化密钥,一般我们填入5和3。  然后,点击`Initalize`初始化按钮,就可以初始化一个`root token`和5个`key`。  然后,我们把这些密钥下载下来,并保存好。  下载的JSON文件格式如下所示: ```json { "keys": [ "17f354a86e8ac3b23312eca344e9793e68cee424d4d1fc3c747411204c79e5f8dc", "9db7ef9118d89a3c8b6921a8d36c156788b2267eea8e8a2e5af70b8a3d75c0d5d4", "fd0511f731f0f5b40ca8449b9773526ebefa1b3cadc551cf3fbe28eb0ee91da520", "21debbcbcbeed7b582bb8e6f60c91a810ec6e1289a909ea3f9036a85af508d5901", "7741aace47a2ac3ab4d3899000f63e375e86d966939a27dd113d32417fe5388828" ], "keys_base64": [ "F/NUqG6Kw7IzEuyjROl5PmjO5CTU0fw8dHQRIEx55fjc", "nbfvkRjYmjyLaSGo02wVZ4iyJn7qjoouWvcLij11wNXU", "/QUR9zHw9bQMqESbl3NSbr76GzytxVHPP74o6w7pHaUg", "Id67y8vu17WCu45vYMkagQ7G4SiakJ6j+QNqha9QjVkB", "d0GqzkeirDq004mQAPY+N16G2WaTmifdET0yQX/lOIgo" ], "root_token": "hvs.fcHLUHa1pcBYdGHXYACm5knQ" } ``` 然后,我们输入3把不同的`key`,就可以进入系统了。  接下来,就是熟悉的登录界面了,我们使用`root token`就可以登录了。  登录成功界面如下,在这里面我们可以进行配置。  ### 5.3 服务配置 #### 5.3.1 配置Secrets - Secrets Engines:与该服务在k8s中的服务名一致(如k8s中的服务名为`frfw-api`,则该引擎名也为`frfw-api`) - Secrets:每个Secrets Engines下,可以配置多个Secrets,每个Secrets 的命名则根据运行的环境变量来命名,如: - k8s-uat:k8s uat 环境 - k8s-prod:k8s prod 环境 - ......  #### 5.3.2 配置Policy 然后,我们根据创建的Secrets来配置策略,策略的命名规则如下: ```sh 引擎名 + Secrets名 + policy后缀 ``` 比如,我们在`frfw-api`下创建了`k8s-uat`和`k8s-prod`两个Secrets,那么,我们就来创建对应的策略。  `frfw-api-k8s-prod`下面的配置如下: ```sh # 只能够读取 frfw-api 下 k8s-prod 配置内容 path "frfw-api/data/k8s-prod" { capabilities = ["read"] } ``` #### 5.3.3 创建授权 ##### 1. 创建AppRole 首先,创建一个AppRole授权模式,命名为`approle`。  ##### 2. 创建角色 在`approle`授权模式下,创建一个角色(UI界面无法实现,需要使用CLI命令行实现)。 ```sh vault write auth/approle/role/{角色名} \ secret_id_bound_cidrs="0.0.0.0/0" \ secret_id_ttl=24h \ secret_id_num_uses=5000 \ token_bound_cidrs="0.0.0.0/0" \ token_num_uses=5000 \ token_ttl=24h \ token_max_ttl=24h \ token_policies="{策略}" ``` 执行结果如下。  ##### 3. 查看角色信息 使用下面命令,查看创建的角色信息。 ```sh vault read auth/approle/role/demo-role ```  ##### 4. 获取角色RoleID 现在,我们需要通过该角色获取Role ID。 我们可以获取Role ID通过下面的命令: ```sh vault read auth/approle/role/demo-role/role-id ``` 执行结果如下。  ##### 5. 生成角色SecretID 然后,我们写入一个SecretID,通过下面命令: ```sh vault write -f auth/approle/role/demo-role/secret-id ``` 执行结果如下:  获取到的SecretID要保存好,否则要再次生成。 现在,我们得到了: - role_id 070b6304-6847-6755-498b-f572bb8d4855 - secret_id 8727d0db-beaa-efb4-1ce8-ab641cb72900 - secret_id_accessor 3438549f-2841-3c97-dfed-909bcfe0e7b8 ##### 6. 获取Token 然后,我们获取Token通过下面的命令: ```sh vault write auth/approle/login role_id=Your_roleID secret_id=Your_secretID ```  ##### 7. 登录系统 我们就得到了Token,然后通过这个Token就可以登录系统了。  登录成功后,就只能看到配置策略下的Secrets内容了。  ### 5.4 Node.js实现 `Node.js`项目引用的是`node-vault`库实现,代码如下: ```js require('dot-env'); // 创建实例对象 const vault = require('node-vault')({ apiVersion: 'v1', // API 版本,默认 endpoint: 'http://127.0.0.1:8200', // Vault接口地址 }); const roleId = process.env.ROLE_ID; const secretId = process.env.SECRET_ID; const run = async () => { // 1. AppRole登录,获取Token const result = await vault.approleLogin({ role_id: roleId, secret_id: secretId, }); vault.token = result.auth.client_token; // 2. 读取配置数据 const { data } = await vault.read('frfw-api/data/test'); console.log(data); }; run(); ``` ---
