-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #75 from AlibabaCloudLandingZone/solution-tvm/0.0.1
solution-tvm/0.0.1
- Loading branch information
Showing
16 changed files
with
775 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
target/ | ||
!.mvn/wrapper/maven-wrapper.jar | ||
!**/src/main/**/target/ | ||
!**/src/test/**/target/ | ||
|
||
### IntelliJ IDEA ### | ||
.idea/ | ||
|
||
### Eclipse ### | ||
.apt_generated | ||
.classpath | ||
.factorypath | ||
.project | ||
.settings | ||
.springBeans | ||
.sts4-cache | ||
|
||
### NetBeans ### | ||
/nbproject/private/ | ||
/nbbuild/ | ||
/dist/ | ||
/nbdist/ | ||
/.nb-gradle/ | ||
build/ | ||
!**/src/main/**/build/ | ||
!**/src/test/**/build/ | ||
|
||
### VS Code ### | ||
.vscode/ | ||
|
||
### Mac OS ### | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
# 通过TVM实现临时凭证的获取和使用 | ||
|
||
在典型的服务端和客户端架构下,客户端如果需要访问阿里云,比如基于OSS的用户文件上传下载、使用SLS记录客户端日志等等场景,常见的方式是在客户端使用RAM用户的访问密钥(AccessKey)来完成,但是在客户端中使用长期有效的访问密钥,可能会导致访问密钥泄露,进而引起安全问题。 | ||
|
||
本方案介绍了一种在客户端获取并使用STS临时凭证的方式,通过STS临时凭证访问阿里云,无需透露长期AccessKey,减少密钥泄露的风险。同时,通过会话权限策略,可以进行精细化的权限管控,避免越权问题。 | ||
|
||
这里针对本方案提供了Java SpringBoot的代码示例,帮助您快速完成应用改造,减少开发和部署的复杂度。 | ||
|
||
## 使用步骤 | ||
|
||
### 目录结构说明 | ||
|
||
``` | ||
. | ||
└── code-example | ||
└── java | ||
└── spring-boot # Java SpringBoot示例代码 | ||
``` | ||
|
||
### Java示例代码 | ||
|
||
``` | ||
java/spring-boot/src/main | ||
├── java/org/example | ||
│ ├── Application.java | ||
│ ├── config | ||
│ │ ├── CredentialConfig.java # 初始化凭据客户端 | ||
│ │ └── StsClientConfig.java # 初始化STS客户端 | ||
│ ├── controller | ||
│ │ └── TvmController.java | ||
│ └── service | ||
│ ├── StsTokenVendor.java # 获取STS Token | ||
│ ├── TokenVendingMachine.java | ||
│ └── policy | ||
│ ├── PolicyGenerator.java # 生成Session Policy | ||
│ └── PolicyTemplateLoader.java # 加载权限模版 | ||
└── resources | ||
├── application.properties | ||
├── policy-templates # 权限模版 | ||
│ ├── OssTemplate.json | ||
│ └── SlsTemplate.json | ||
└── static # 前端示例 | ||
├── oss.html # OSS示例 | ||
└── sls.html # SLS示例 | ||
``` | ||
|
||
#### 环境要求 | ||
|
||
该示例代码需要在ECS环境中执行,执行前,请确保运行环境中已配置好Java和Maven。 | ||
|
||
1. Java Development Kit (JDK):确保已安装Java 8或更高版本。 | ||
2. Apache Maven:确保已安装Maven 3.6.0或更高版本。 | ||
|
||
运行以下命令来检查Java安装: | ||
|
||
```bash | ||
java -version | ||
``` | ||
|
||
运行以下命令来检查Maven安装: | ||
|
||
```bash | ||
maven -version | ||
``` | ||
|
||
#### 本地运行 | ||
|
||
1. 首先您需要配置凭证信息,建议您通过环境变量进行配置: | ||
|
||
``` | ||
ALIBABA_CLOUD_ACCESS_KEY_ID=<您的AccessKey ID>;ALIBABA_CLOUD_ACCESS_KEY_SECRET=<您的AccessKey Secret> | ||
``` | ||
> 您也可以将该项目部署到阿里云上,强烈建议您使用临时凭证来代替固定AccessKey。 | ||
2. 接着您需要进行应用配置,打开 `resources/application.properties` 进行如下配置: | ||
``` | ||
# 服务启动端口个 | ||
server.port = 7001 | ||
# 地域,以杭州地域为例 | ||
region.id=cn-hangzhou | ||
# 请填写要扮演的业务RAM角色ARN,格式为acs:ram::${账号 ID}:role/${角色名称} | ||
role.arn= | ||
# 请填写OSS Bucket名称,示例中会从该Bucket中上传下载文件 | ||
oss.bucket= | ||
# 请填写SLS Project名称 | ||
sls.project= | ||
``` | ||
同时,在`resources/static/oss.html`和`resources/static/sls.html`中配置对应的信息。 | ||
3. 启动`Application.java`,浏览器打开`resources/static/oss.html`和`resources/static/sls.html`体验Web端示例 |
81 changes: 81 additions & 0 deletions
81
solution/solution-tvm/code-example/java/spring-boot/pom.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
<parent> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-parent</artifactId> | ||
<version>2.3.4.RELEASE</version> | ||
</parent> | ||
<groupId>org.example</groupId> | ||
<artifactId>spring-boot</artifactId> | ||
<version>1.0-SNAPSHOT</version> | ||
<packaging>jar</packaging> | ||
|
||
<properties> | ||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
<maven.compiler.source>1.8</maven.compiler.source> | ||
<maven.compiler.target>1.8</maven.compiler.target> | ||
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion> | ||
<exec.cleanupDaemonThreads>false</exec.cleanupDaemonThreads> | ||
</properties> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-web</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-aop</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>com.samskivert</groupId> | ||
<artifactId>jmustache</artifactId> | ||
<version>1.15</version> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>com.alibaba.fastjson2</groupId> | ||
<artifactId>fastjson2</artifactId> | ||
<version>2.0.51</version> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>org.projectlombok</groupId> | ||
<artifactId>lombok</artifactId> | ||
<version>1.18.6</version> | ||
</dependency> | ||
|
||
<!--1.0 sdk--> | ||
<dependency> | ||
<groupId>com.aliyun</groupId> | ||
<artifactId>aliyun-java-sdk-core</artifactId> | ||
<version>4.7.1</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.aliyun</groupId> | ||
<artifactId>aliyun-java-sdk-sts</artifactId> | ||
<version>3.1.2</version> | ||
</dependency> | ||
|
||
<!--2.0 sdk--> | ||
<dependency> | ||
<groupId>com.aliyun</groupId> | ||
<artifactId>sts20150401</artifactId> | ||
<version>1.1.4</version> | ||
</dependency> | ||
|
||
<!-- Requires: version >= 0.3.4 --> | ||
<!-- 推荐使用最新版本 --> | ||
<!--获取所有已发布的版本列表,请参见https://github.com/aliyun/credentials-java/blob/master/ChangeLog.txt--> | ||
<dependency> | ||
<groupId>com.aliyun</groupId> | ||
<artifactId>credentials-java</artifactId> | ||
<version>0.3.5</version> | ||
</dependency> | ||
</dependencies> | ||
</project> |
11 changes: 11 additions & 0 deletions
11
...ion/solution-tvm/code-example/java/spring-boot/src/main/java/org/example/Application.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package org.example; | ||
|
||
import org.springframework.boot.SpringApplication; | ||
import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
|
||
@SpringBootApplication | ||
public class Application { | ||
public static void main(String[] args) { | ||
SpringApplication.run(Application.class, args); | ||
} | ||
} |
37 changes: 37 additions & 0 deletions
37
...-tvm/code-example/java/spring-boot/src/main/java/org/example/config/CredentialConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package org.example.config; | ||
|
||
import com.aliyun.credentials.Client; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
@Configuration | ||
public class CredentialConfig { | ||
|
||
// 初始化凭据客户端,Credential SDK Client 应该是单例,不要每次请求都重新 new 一个,避免内存泄露 | ||
// 借助Credentials工具的默认凭据链,您可以用同一套代码,通过程序之外的配置来控制不同环境下的凭据获取方式 | ||
// 当您在初始化凭据客户端不传入任何参数时,Credentials工具将会尝试按照如下顺序查找相关凭据信息(优先级由高到低): | ||
// 1. 使用系统属性 | ||
// 2. 使用环境变量 | ||
// 3. 使用OIDC RAM角色 | ||
// 4. 使用配置文件 | ||
// 5. 使用ECS实例RAM角色(需要通过环境变量 ALIBABA_CLOUD_ECS_METADATA 指定 ECS 实例角色名称;通过环境变量 ALIBABA_CLOUD_ECS_IMDSV2_ENABLE=true 开启在加固模式下获取STS Token) | ||
// https://help.aliyun.com/zh/sdk/developer-reference/v2-manage-access-credentials#3ca299f04bw3c | ||
// 要使用默认凭据链,初始化 Client 时,必须使用空的构造函数,不能配置 Config 入参 | ||
@Bean(name = "credentialClient") | ||
Client getCredentialClient() { | ||
return new Client(); | ||
} | ||
|
||
// 除了使用上面的默认凭据链,您也可以在代码中显式配置,来初始化凭据客户端 | ||
// 如下所示,可以进行显式配置,以ECS实例角色为例 | ||
//@Bean(name = "credentialClient") | ||
//Client getCredentialClient() { | ||
// Config config = new Config() | ||
// .setType("ecs_ram_role") | ||
// // 选填,该ECS实例角色的角色名称,不填会自动获取,建议加上以减少请求次数 | ||
// .setRoleName("<请填写ECS实例角色的角色名称>") | ||
// // 在加固模式下获取STS Token,强烈建议开启 | ||
// .setEnableIMDSv2(true); | ||
// return new Client(config); | ||
//} | ||
} |
26 changes: 26 additions & 0 deletions
26
...n-tvm/code-example/java/spring-boot/src/main/java/org/example/config/StsClientConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package org.example.config; | ||
|
||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
@Configuration | ||
public class StsClientConfig { | ||
|
||
@Value("${region.id}") | ||
String regionId; | ||
|
||
@Autowired | ||
com.aliyun.credentials.Client credentialClient; | ||
|
||
// 初始化阿里云 V2 版本 STS 的 SDK 客户端 | ||
// SDK Client 应该是单例,不要每次请求都重新 New 一个,避免内存泄露 | ||
@Bean(name = "stsClient") | ||
com.aliyun.sts20150401.Client getStsClient() throws Exception { | ||
com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config() | ||
.setCredential(credentialClient) | ||
.setRegionId(regionId); | ||
return new com.aliyun.sts20150401.Client(config); | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
...tvm/code-example/java/spring-boot/src/main/java/org/example/controller/TvmController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package org.example.controller; | ||
|
||
import com.aliyun.sts20150401.models.AssumeRoleResponseBody; | ||
import org.example.service.TokenVendingMachine; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.web.bind.annotation.CrossOrigin; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RequestHeader; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
@RestController | ||
public class TvmController { | ||
|
||
@Autowired | ||
TokenVendingMachine tokenVendingMachine; | ||
|
||
// 测试示例使用,配置了 CORS 跨域 | ||
@CrossOrigin(origins = "*", allowedHeaders = "*", maxAge = 86400) | ||
@GetMapping("/vendToken") | ||
public AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials vendToken(@RequestHeader("Custom-Identity") String identity) { | ||
// 根据自身应用需要,进行请求的合法性校验 | ||
// 本示例只是演示使用,不会对请求身份等进行合法性校验 | ||
return tokenVendingMachine.vendToken(identity); | ||
} | ||
} |
76 changes: 76 additions & 0 deletions
76
...n-tvm/code-example/java/spring-boot/src/main/java/org/example/service/StsTokenVendor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package org.example.service; | ||
|
||
import com.aliyun.sts20150401.models.AssumeRoleRequest; | ||
import com.aliyun.sts20150401.models.AssumeRoleResponse; | ||
import com.aliyun.sts20150401.models.AssumeRoleResponseBody; | ||
import com.aliyun.tea.TeaException; | ||
import com.aliyun.tea.TeaUnretryableException; | ||
import com.aliyun.teautil.models.RuntimeOptions; | ||
import lombok.Builder; | ||
|
||
@Builder | ||
public class StsTokenVendor { | ||
|
||
private final com.aliyun.sts20150401.Client stsClient; | ||
|
||
/** | ||
* 要扮演的RAM角色ARN,acs:ram::${账号 ID}:role/${角色名称} | ||
*/ | ||
private final String roleArn; | ||
|
||
/** | ||
* 角色会话名称 | ||
*/ | ||
private final String roleSessionName; | ||
|
||
/** | ||
* 会话权限策略,可以进一步缩小权限,进行精细化管控 | ||
*/ | ||
private final String sessionPolicy; | ||
|
||
/** | ||
* STS Token有效期,单位:秒 | ||
*/ | ||
private final Long durationSeconds; | ||
|
||
public AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials vendToken() { | ||
RuntimeOptions runtimeOptions = new RuntimeOptions() | ||
// 开启自动重试机制 | ||
.setAutoretry(true) | ||
// 设置自动重试次数,默认3次 | ||
.setMaxAttempts(3); | ||
AssumeRoleRequest assumeRoleRequest = new AssumeRoleRequest() | ||
.setRoleArn(roleArn) | ||
.setRoleSessionName(roleSessionName) | ||
.setPolicy(sessionPolicy) | ||
.setDurationSeconds(durationSeconds); | ||
try { | ||
AssumeRoleResponse assumeRoleResponse = stsClient.assumeRoleWithOptions(assumeRoleRequest, runtimeOptions); | ||
return assumeRoleResponse.getBody().getCredentials(); | ||
} catch (TeaUnretryableException e) { | ||
// 该异常主要是因为网络问题造成,一般是网络问题达到最大重试次数后抛出,可以通过exception.getLastRequest来查询错误发生时的请求信息。 | ||
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。 | ||
e.printStackTrace(); | ||
// 打印错误信息 | ||
System.out.println(e.getMessage()); | ||
// 打印请求记录 | ||
System.out.println(e.getLastRequest()); | ||
throw e; | ||
} catch (TeaException e) { | ||
// 在SDK的请求中主要以业务报错为主的异常 | ||
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。 | ||
e.printStackTrace(); | ||
// 打印错误码 | ||
System.out.println(e.getCode()); | ||
// 打印错误信息,错误信息中包含 RequestId | ||
System.out.println(e.getMessage()); | ||
// 打印服务端返回的具体错误内容 | ||
System.out.println(e.getData()); | ||
throw e; | ||
} catch (Exception e) { | ||
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。 | ||
e.printStackTrace(); | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
} |
Oops, something went wrong.