Skip to content

Commit

Permalink
feat: add imds and external uri in default chain && resolve credentia…
Browse files Browse the repository at this point in the history
…ls timeout
  • Loading branch information
徐文平 authored and yndu13 committed Nov 24, 2024
1 parent 7a0786d commit 3d2787b
Show file tree
Hide file tree
Showing 19 changed files with 589 additions and 74 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ jobs:
fail-fast: false

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@
"typescript": "^3.7.5"
},
"dependencies": {
"@alicloud/tea-typescript": "^1.5.3",
"httpx": "^2.2.0",
"@alicloud/tea-typescript": "^1.8.0",
"httpx": "^2.3.3",
"ini": "^1.3.5",
"kitx": "^2.0.0"
},
Expand Down
18 changes: 17 additions & 1 deletion src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import RAMRoleARNCredentialsProvider from './providers/ram_role_arn';
import OIDCRoleArnCredentialsProvider from './providers/oidc_role_arn';
import ECSRAMRoleCredentialsProvider from './providers/ecs_ram_role';
import DefaultCredentialsProvider from './providers/default';
import URICredentialsProvider from './providers/uri';

export { Config };

Expand Down Expand Up @@ -140,6 +141,8 @@ export default class Credential implements ICredential {
this.credential = new InnerCredentialsClient('ecs_ram_role', ECSRAMRoleCredentialsProvider.builder()
.withRoleName(config.roleName)
.withDisableIMDSv1(config.disableIMDSv1)
.withReadTimeout(config.timeout)
.withConnectTimeout(config.connectTimeout)
.build());
break;
case 'ram_role_arn': {
Expand All @@ -162,6 +165,12 @@ export default class Credential implements ICredential {
.withPolicy(config.policy)
.withDurationSeconds(config.roleSessionExpiration)
.withRoleSessionName(config.roleSessionName)
.withReadTimeout(config.timeout)
.withConnectTimeout(config.connectTimeout)
.withEnableVpc(config.enableVpc)
.withStsEndpoint(config.stsEndpoint)
.withStsRegionId(config.stsRegionId)
.withExternalId(config.externalId)
// .withHttpOptions(runtime)
.build());
}
Expand All @@ -174,6 +183,9 @@ export default class Credential implements ICredential {
.withRoleSessionName(config.roleSessionName)
.withPolicy(config.policy)
.withDurationSeconds(config.roleSessionExpiration)
.withStsEndpoint(config.stsEndpoint)
.withReadTimeout(config.timeout)
.withConnectTimeout(config.connectTimeout)
.build());
break;
case 'rsa_key_pair':
Expand All @@ -183,7 +195,11 @@ export default class Credential implements ICredential {
this.credential = new BearerTokenCredential(config.bearerToken);
break;
case 'credentials_uri':
this.credential = new URICredential(config.credentialsURI);
this.credential = new InnerCredentialsClient('credentials_uri', URICredentialsProvider.builder()
.withCredentialsURI(config.credentialsURI)
.withReadTimeout(config.timeout)
.withConnectTimeout(config.connectTimeout)
.build());
break;
default:
throw new Error('Invalid type option, support: access_key, sts, ecs_ram_role, ram_role_arn, rsa_key_pair, credentials_uri');
Expand Down
16 changes: 16 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ export default class Config extends $tea.Model {
oidcProviderArn: string;
oidcTokenFilePath: string;
type?: string;
externalId?: string;
stsEndpoint?: string;
timeout?: number;
connectTimeout?: number;

static names(): { [key: string]: string } {
return {
Expand All @@ -32,6 +36,12 @@ export default class Config extends $tea.Model {
policy: 'policy',
roleSessionExpiration: 'roleSessionExpiration',
roleSessionName: 'roleSessionName',
externalId: 'externalId',
stsEndpoint: 'stsEndpoint',
stsRegionId: 'stsRegionId',
enableVpc: 'enableVpc',
timeout: 'readTimeout',
connectTimeout: 'connectTimeout',
publicKeyId: 'publicKeyId',
privateKeyFile: 'privateKeyFile',
roleName: 'roleName',
Expand All @@ -56,6 +66,12 @@ export default class Config extends $tea.Model {
policy: 'string',
roleSessionExpiration: 'number',
roleSessionName: 'string',
externalId: 'string',
stsEndpoint: 'string',
stsRegionId: 'string',
enableVpc: 'string',
timeout: 'number',
connectTimeout: 'number',
publicKeyId: 'string',
privateKeyFile: 'string',
roleName: 'string',
Expand Down
6 changes: 5 additions & 1 deletion src/ecs_ram_role_credential.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export default class EcsRamRoleCredential extends SessionCredential implements I
runtime: { [key: string]: any };
metadataToken?: string;
staleTime?: number
readTimeout?: number;
connectTimeout?: number;

constructor(roleName: string = '', runtime: { [key: string]: any } = {}, enableIMDSv2: boolean = false, metadataTokenDuration: number = 21600) {
const conf = new Config({
Expand Down Expand Up @@ -58,7 +60,9 @@ export default class EcsRamRoleCredential extends SessionCredential implements I
options = {
headers: {
'X-aliyun-ecs-metadata-token': this.metadataToken
}
},
readTimeout: this.readTimeout,
connectTimeout: this.connectTimeout
}
}
const roleName = await this.getRoleName();
Expand Down
9 changes: 8 additions & 1 deletion src/providers/cli_profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class CLIProfileCredentialsProviderBuilder {
this.profileName = process.env.ALIBABA_CLOUD_PROFILE;
}

if (process.env.ALIBABA_CLOUD_CLI_PROFILE_DISABLED === 'true') {
if (process.env.ALIBABA_CLOUD_CLI_PROFILE_DISABLED && process.env.ALIBABA_CLOUD_CLI_PROFILE_DISABLED.toLowerCase() === 'true') {
throw new Error('the CLI profile is disabled');
}

Expand All @@ -50,6 +50,9 @@ interface Profile {
ram_role_name: string;
oidc_token_file: string;
oidc_provider_arn: string;
sts_endpoint: string,
enable_vpc: boolean,
duration_seconds: number
}

class Configuration {
Expand Down Expand Up @@ -121,6 +124,8 @@ export default class CLIProfileCredentialsProvider implements CredentialsProvide
.withRoleSessionName(p.ram_session_name)
.withDurationSeconds(p.expired_seconds)
.withStsRegionId(p.sts_region)
.withStsEndpoint(p.sts_endpoint)
.withEnableVpc(p.enable_vpc)
.build();
}
case 'EcsRamRole':
Expand All @@ -133,6 +138,8 @@ export default class CLIProfileCredentialsProvider implements CredentialsProvide
.withStsRegionId(p.sts_region)
.withDurationSeconds(p.expired_seconds)
.withRoleSessionName(p.ram_session_name)
.withDurationSeconds(p.duration_seconds)
.withEnableVpc(p.enable_vpc)
.build();
case 'ChainableRamRoleArn': {
const previousProvider = this.getCredentialsProvider(conf, p.source_profile);
Expand Down
27 changes: 16 additions & 11 deletions src/providers/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import CLIProfileCredentialsProvider from './cli_profile';
import ECSRAMRoleCredentialsProvider from './ecs_ram_role';
import EnvironmentVariableCredentialsProvider from './env';
import OIDCRoleArnCredentialsProvider from './oidc_role_arn';
import URICredentialsProvider from './uri';
import ProfileCredentialsProvider from './profile';

export default class DefaultCredentialsProvider implements CredentialsProvider {
private readonly providers: CredentialsProvider[];
private lastUsedProvider : CredentialsProvider;
private lastUsedProvider: CredentialsProvider;
static builder() {
return new DefaultCredentialsProviderBuilder();
}
Expand Down Expand Up @@ -48,17 +49,21 @@ export default class DefaultCredentialsProvider implements CredentialsProvider {
}

// Add IMDS
if (process.env.ALIBABA_CLOUD_ECS_METADATA) {
try {
const ecsRamRoleProvider = ECSRAMRoleCredentialsProvider.builder().withRoleName(process.env.ALIBABA_CLOUD_ECS_METADATA).build();
this.providers.push(ecsRamRoleProvider);
}
catch (ex) {
// ignore
}
try {
const ecsRamRoleProvider = ECSRAMRoleCredentialsProvider.builder().withRoleName(process.env.ALIBABA_CLOUD_ECS_METADATA).build();
this.providers.push(ecsRamRoleProvider);
} catch (ex) {
// ignore
}

// TODO: ALIBABA_CLOUD_CREDENTIALS_URI check
// credentials uri
try {
const uriProvider = URICredentialsProvider.builder().withCredentialsURI(process.env.ALIBABA_CLOUD_CREDENTIALS_URI).build();
this.providers.push(uriProvider);
}
catch (ex) {
// ignore
}
}

async getCredentials(): Promise<Credentials> {
Expand All @@ -78,7 +83,7 @@ export default class DefaultCredentialsProvider implements CredentialsProvider {
let inner;
try {
inner = await provider.getCredentials();
} catch(ex) {
} catch (ex) {
errors.push(ex);
continue;
}
Expand Down
33 changes: 30 additions & 3 deletions src/providers/ecs_ram_role.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export default class ECSRAMRoleCredentialsProvider implements CredentialsProvide
private expirationTimestamp: number
// for mock
private doRequest = doRequest;
private readonly readTimeout: number;
private readonly connectTimeout: number;

static builder(): ECSRAMRoleCredentialsProviderBuilder {
return new ECSRAMRoleCredentialsProviderBuilder();
Expand All @@ -22,6 +24,8 @@ export default class ECSRAMRoleCredentialsProvider implements CredentialsProvide
constructor(builder: ECSRAMRoleCredentialsProviderBuilder) {
this.roleName = builder.roleName;
this.disableIMDSv1 = builder.disableIMDSv1;
this.readTimeout = builder.readTimeout;
this.connectTimeout = builder.connectTimeout;
}

async getCredentials(): Promise<Credentials> {
Expand Down Expand Up @@ -58,6 +62,8 @@ export default class ECSRAMRoleCredentialsProvider implements CredentialsProvide
.withHeaders({
'x-aliyun-ecs-metadata-token-ttl-seconds': `${defaultMetadataTokenDuration}`
})
.withReadTimeout(this.readTimeout || 1000)
.withConnectTimeout(this.connectTimeout || 1000)
.build();

// ConnectTimeout: 5 * time.Second,
Expand All @@ -82,7 +88,9 @@ export default class ECSRAMRoleCredentialsProvider implements CredentialsProvide
.withMethod('GET')
.withProtocol('http')
.withHost('100.100.100.200')
.withPath('/latest/meta-data/ram/security-credentials/');
.withPath('/latest/meta-data/ram/security-credentials/')
.withReadTimeout(this.readTimeout || 1000)
.withConnectTimeout(this.connectTimeout || 1000);

const metadataToken = await this.getMetadataToken();
if (metadataToken !== null) {
Expand Down Expand Up @@ -114,7 +122,9 @@ export default class ECSRAMRoleCredentialsProvider implements CredentialsProvide
.withMethod('GET')
.withProtocol('http')
.withHost('100.100.100.200')
.withPath(`/latest/meta-data/ram/security-credentials/${roleName}`);
.withPath(`/latest/meta-data/ram/security-credentials/${roleName}`)
.withReadTimeout(this.readTimeout || 1000)
.withConnectTimeout(this.connectTimeout || 1000);

// ConnectTimeout: 5 * time.Second,
// ReadTimeout: 5 * time.Second,
Expand Down Expand Up @@ -160,6 +170,8 @@ export default class ECSRAMRoleCredentialsProvider implements CredentialsProvide
class ECSRAMRoleCredentialsProviderBuilder {
roleName: string
disableIMDSv1: boolean
readTimeout?: number;
connectTimeout?: number;

constructor() {
this.disableIMDSv1 = false;
Expand All @@ -175,14 +187,29 @@ class ECSRAMRoleCredentialsProviderBuilder {
return this;
}

withReadTimeout(readTimeout: number): ECSRAMRoleCredentialsProviderBuilder{
this.readTimeout = readTimeout
return this;
}

withConnectTimeout(connectTimeout: number): ECSRAMRoleCredentialsProviderBuilder{
this.connectTimeout = connectTimeout
return this;
}

build(): ECSRAMRoleCredentialsProvider {
// 允许通过环境变量强制关闭 IMDS
if (process.env.ALIBABA_CLOUD_ECS_METADATA_DISABLED && process.env.ALIBABA_CLOUD_ECS_METADATA_DISABLED.toLowerCase() === 'true') {
throw new Error('IMDS credentials is disabled');
}

// 设置 roleName 默认值
if (!this.roleName) {
this.roleName = process.env.ALIBABA_CLOUD_ECS_METADATA;
}

// 允许通过环境变量强制关闭 V1
if (process.env.ALIBABA_CLOUD_IMDSV1_DISABLED === 'true') {
if (process.env.ALIBABA_CLOUD_IMDSV1_DISABLED && process.env.ALIBABA_CLOUD_IMDSV1_DISABLED.toLowerCase() === 'true') {
this.disableIMDSv1 = true;
}

Expand Down
31 changes: 30 additions & 1 deletion src/providers/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ export class Request {
readonly path: any;
readonly bodyForm: { [key: string]: string; };
readonly bodyBytes: Buffer;
readonly url: string;
readonly readTimeout: number;
readonly connectTimeout: number;

static builder() {
return new RequestBuilder();
Expand All @@ -23,9 +26,15 @@ export class Request {
this.headers = builder.headers;
this.bodyForm = builder.bodyForm;
this.bodyBytes = builder.bodyBytes;
this.url = builder.url;
this.readTimeout = builder.readTimeout;
this.connectTimeout = builder.connectTimeout;
}

toRequestURL(): string {
if(this.url){
return this.url;
}
let url = `${this.protocol}://${this.host}${this.path}`;
if (this.queries && Object.keys(this.queries).length > 0) {
url += `?` + querystringify(this.queries)
Expand All @@ -43,6 +52,9 @@ export class RequestBuilder {
headers: { [key: string]: string; };
bodyForm: { [key: string]: string; };
bodyBytes: Buffer;
readTimeout: number;
connectTimeout: number;
url: string;

build(): Request {
// set default values
Expand Down Expand Up @@ -99,6 +111,21 @@ export class RequestBuilder {
this.bodyForm = bodyForm;
return this;
}

withURL(url: string){
this.url = url;
return this;
}

withReadTimeout(readTimeout: number) {
this.readTimeout = readTimeout;
return this;
}

withConnectTimeout(connectTimeout: number) {
this.connectTimeout = connectTimeout;
return this;
}
}

export class Response {
Expand Down Expand Up @@ -168,7 +195,9 @@ export async function doRequest(req: Request): Promise<Response> {
const response = await httpx.request(url, {
method: req.method,
data: body,
headers: req.headers
headers: req.headers,
readTimeout: req.readTimeout,
connectTimeout: req.connectTimeout
});

const responseBody = await httpx.read(response, '');
Expand Down
Loading

0 comments on commit 3d2787b

Please sign in to comment.