-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add cli profile credentials provider
- Loading branch information
1 parent
e7464df
commit 6221e85
Showing
10 changed files
with
586 additions
and
10 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
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
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,178 @@ | ||
import { readFile } from 'fs'; | ||
import { promisify } from 'util'; | ||
|
||
import path from 'path'; | ||
import os from 'os'; | ||
import Credentials from '../credentials'; | ||
import CredentialsProvider from '../credentials_provider' | ||
import StaticAKCredentialsProvider from './static_ak'; | ||
import RAMRoleARNCredentialsProvider from './ram_role_arn'; | ||
import OIDCRoleArnCredentialsProvider from './oidc_role_arn'; | ||
import ECSRAMRoleCredentialsProvider from './ecs_ram_role'; | ||
|
||
const readFileAsync = promisify(readFile); | ||
|
||
class CLIProfileCredentialsProviderBuilder { | ||
profileName: string; | ||
build(): CLIProfileCredentialsProvider { | ||
// 优先级: | ||
// 1. 使用显示指定的 profileName | ||
// 2. 使用环境变量(ALIBABA_CLOUD_PROFILE)制定的 profileName | ||
// 3. 使用 CLI 配置中的当前 profileName | ||
if (!this.profileName) { | ||
this.profileName = process.env.ALIBABA_CLOUD_PROFILE; | ||
} | ||
|
||
if (process.env.ALIBABA_CLOUD_CLI_PROFILE_DISABLED === 'true') { | ||
throw new Error('the CLI profile is disabled'); | ||
} | ||
|
||
return new CLIProfileCredentialsProvider(this); | ||
} | ||
|
||
withProfileName(profileName: string) { | ||
this.profileName = profileName; | ||
return this; | ||
} | ||
} | ||
|
||
interface Profile { | ||
name: string; | ||
mode: string; | ||
access_key_id: string; | ||
access_key_secret: string; | ||
region_id: string; | ||
ram_role_arn: string; | ||
ram_session_name: string; | ||
expired_seconds: number; | ||
sts_region: string; | ||
source_profile: string; | ||
ram_role_name: string; | ||
oidc_token_file: string; | ||
oidc_provider_arn: string; | ||
} | ||
|
||
class Configuration { | ||
current: string; | ||
profiles: Profile[]; | ||
} | ||
|
||
export async function getConfiguration(cfgPath: string): Promise<Configuration> { | ||
let content: string; | ||
try { | ||
content = await readFileAsync(cfgPath, 'utf8'); | ||
} catch (ex) { | ||
throw new Error(`reading aliyun cli config from '${cfgPath}' failed.`); | ||
} | ||
let conf: Configuration; | ||
try { | ||
conf = JSON.parse(content) as Configuration; | ||
} catch (ex) { | ||
throw new Error(`parse aliyun cli config from '${cfgPath}' failed: ${content}`); | ||
} | ||
|
||
if (!conf || !conf.profiles || conf.profiles.length === 0) { | ||
throw new Error(`no any configured profiles in '${cfgPath}'`); | ||
} | ||
return conf; | ||
} | ||
|
||
export function getProfile(conf: Configuration, profileName: string): Profile { | ||
for (const p of conf.profiles) { | ||
if (p.name === profileName) { | ||
return p; | ||
} | ||
} | ||
|
||
throw new Error(`unable to get profile with '${profileName}'`); | ||
} | ||
|
||
export default class CLIProfileCredentialsProvider implements CredentialsProvider { | ||
static builder(): CLIProfileCredentialsProviderBuilder { | ||
return new CLIProfileCredentialsProviderBuilder(); | ||
} | ||
private readonly profileName: string; | ||
private innerProvider: CredentialsProvider; | ||
|
||
// used for mock | ||
private homedir: string = os.homedir(); | ||
|
||
constructor(builder: CLIProfileCredentialsProviderBuilder) { | ||
this.profileName = builder.profileName; | ||
} | ||
|
||
private getCredentialsProvider(conf: Configuration, profileName: string): CredentialsProvider { | ||
const p = getProfile(conf, profileName); | ||
switch (p.mode) { | ||
case 'AK': | ||
return StaticAKCredentialsProvider.builder() | ||
.withAccessKeyId(p.access_key_id) | ||
.withAccessKeySecret(p.access_key_secret) | ||
.build(); | ||
case 'RamRoleArn': { | ||
const previousProvider = StaticAKCredentialsProvider.builder() | ||
.withAccessKeyId(p.access_key_id) | ||
.withAccessKeySecret(p.access_key_secret) | ||
.build(); | ||
|
||
return RAMRoleARNCredentialsProvider.builder() | ||
.withCredentialsProvider(previousProvider) | ||
.withRoleArn(p.ram_role_arn) | ||
.withRoleSessionName(p.ram_session_name) | ||
.withDurationSeconds(p.expired_seconds) | ||
.withStsRegionId(p.sts_region) | ||
.build(); | ||
} | ||
case 'EcsRamRole': | ||
return ECSRAMRoleCredentialsProvider.builder().withRoleName(p.ram_role_name).build(); | ||
case 'OIDC': | ||
return OIDCRoleArnCredentialsProvider.builder() | ||
.withOIDCTokenFilePath(p.oidc_token_file) | ||
.withOIDCProviderArn(p.oidc_provider_arn) | ||
.withRoleArn(p.ram_role_arn) | ||
.withStsRegionId(p.sts_region) | ||
.withDurationSeconds(p.expired_seconds) | ||
.withRoleSessionName(p.ram_session_name) | ||
.build(); | ||
case 'ChainableRamRoleArn': { | ||
const previousProvider = this.getCredentialsProvider(conf, p.source_profile); | ||
return RAMRoleARNCredentialsProvider.builder() | ||
.withCredentialsProvider(previousProvider) | ||
.withRoleArn(p.ram_role_arn) | ||
.withRoleSessionName(p.ram_session_name) | ||
.withDurationSeconds(p.expired_seconds) | ||
.withStsRegionId(p.sts_region) | ||
.build(); | ||
} | ||
default: | ||
throw new Error(`unsupported profile mode '${p.mode}'`); | ||
} | ||
} | ||
|
||
async getCredentials(): Promise<Credentials> { | ||
if (!this.innerProvider) { | ||
if (!this.homedir) { | ||
throw new Error('cannot found home dir'); | ||
} | ||
|
||
const cfgPath = path.join(this.homedir, '.aliyun/config.json'); | ||
|
||
const conf = await getConfiguration(cfgPath); | ||
const profileName = this.profileName || conf.current; | ||
this.innerProvider = this.getCredentialsProvider(conf, profileName) | ||
} | ||
|
||
const credentials = await this.innerProvider.getCredentials() | ||
return Credentials.builder() | ||
.withAccessKeyId(credentials.accessKeyId) | ||
.withAccessKeySecret(credentials.accessKeySecret) | ||
.withSecurityToken(credentials.securityToken) | ||
.withProviderName(`${this.getProviderName()}/${this.innerProvider.getProviderName()}`) | ||
.build(); | ||
} | ||
|
||
getProviderName(): string { | ||
return 'cli_profile'; | ||
} | ||
|
||
} |
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 |
---|---|---|
@@ -1,13 +1,73 @@ | ||
[default] | ||
enable = true | ||
type = access_key | ||
access_key_id = access-key-id-04 | ||
access_key_secret = access-key-secret-04 | ||
access_key_id = foo | ||
access_key_secret = bar | ||
|
||
[demo1] | ||
enable = true | ||
[notype] | ||
access_key_id = foo | ||
access_key_secret = bar | ||
|
||
[noak] | ||
type = access_key | ||
access_key_secret = bar | ||
|
||
[emptyak] | ||
type = access_key | ||
access_key_id = | ||
access_key_secret = bar | ||
|
||
[ecs] | ||
type = ecs_ram_role | ||
role_name = EcsRamRoleTest | ||
|
||
[noecs] | ||
type = ecs_ram_role | ||
|
||
[emptyecs] | ||
type = ecs_ram_role | ||
role_name = | ||
|
||
[ram] | ||
type = ram_role_arn | ||
access_key_id = access-key-id-05 | ||
access_key_secret = access-key-secret-05 | ||
role_arn = acs:ram::demo1:role/demo1 | ||
role_session_name = demo1 | ||
access_key_id = foo | ||
access_key_secret = bar | ||
role_arn = role_arn | ||
role_session_name = session_name | ||
|
||
[noram] | ||
type = ram_role_arn | ||
access_key_secret = bar | ||
role_arn = role_arn | ||
role_session_name = session_name | ||
|
||
[emptyram] | ||
type = ram_role_arn | ||
access_key_id = | ||
access_key_secret = bar | ||
role_arn = role_arn | ||
role_session_name = session_name | ||
|
||
[rsa] | ||
type = rsa_key_pair | ||
public_key_id = publicKeyId | ||
private_key_file = ./pk.pem | ||
|
||
[norsa] | ||
type = rsa_key_pair | ||
public_key_id = publicKeyId | ||
|
||
[emptyrsa] | ||
type = rsa_key_pair | ||
public_key_id = publicKeyId | ||
private_key_file = | ||
|
||
[error_rsa] | ||
type = rsa_key_pair | ||
public_key_id = publicKeyId | ||
private_key_file = ./pk_error.pem | ||
|
||
[error_type] | ||
type = error_type | ||
public_key_id = publicKeyId | ||
private_key_file = ./pk_error.pem |
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,51 @@ | ||
{ | ||
"current": "AK", | ||
"profiles": [ | ||
{ | ||
"name": "AK", | ||
"mode": "AK", | ||
"access_key_id": "akid", | ||
"access_key_secret": "secret" | ||
}, | ||
{ | ||
"name": "RamRoleArn", | ||
"mode": "RamRoleArn", | ||
"access_key_id": "akid", | ||
"access_key_secret": "secret", | ||
"ram_role_arn": "arn" | ||
}, | ||
{ | ||
"name": "EcsRamRole", | ||
"mode": "EcsRamRole", | ||
"ram_role_name": "rolename" | ||
}, | ||
{ | ||
"name": "OIDC", | ||
"mode": "OIDC", | ||
"ram_role_arn": "role_arn", | ||
"oidc_token_file": "path/to/oidc/file", | ||
"oidc_provider_arn": "provider_arn" | ||
}, | ||
{ | ||
"name": "ChainableRamRoleArn", | ||
"mode": "ChainableRamRoleArn", | ||
"source_profile": "AK" | ||
}, | ||
{ | ||
"name": "ChainableRamRoleArn2", | ||
"mode": "ChainableRamRoleArn", | ||
"source_profile": "InvalidSource" | ||
}, | ||
{ | ||
"name": "get_credentials_error", | ||
"mode": "RamRoleArn", | ||
"access_key_id": "akid", | ||
"access_key_secret": "secret", | ||
"ram_role_arn": "arn" | ||
}, | ||
{ | ||
"name": "Unsupported", | ||
"mode": "Unsupported" | ||
} | ||
] | ||
} |
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 @@ | ||
invalid config |
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,17 @@ | ||
{ | ||
"current": "default", | ||
"profiles": [ | ||
{ | ||
"name": "default", | ||
"mode": "AK", | ||
"access_key_id": "akid", | ||
"access_key_secret": "secret" | ||
}, | ||
{ | ||
"name": "jacksontian", | ||
"mode": "AK", | ||
"access_key_id": "akid", | ||
"access_key_secret": "secret" | ||
} | ||
] | ||
} |
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 @@ | ||
{} |
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 @@ | ||
mock oidc token |
Oops, something went wrong.