Skip to content

Commit

Permalink
support oidc credential in credential chain && support ALIBABA_CLOUD_…
Browse files Browse the repository at this point in the history
…ROLE_ARN/ALIBABA_CLOUD_OIDC_PROVIDER_ARN/ALIBABA_CLOUD_ROLE_SESSION_NAME
  • Loading branch information
yndu13 committed Jan 31, 2023
1 parent 6b4e639 commit 3bee676
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 8 deletions.
11 changes: 10 additions & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,13 @@ jobs:
run: go test -race -coverprofile=coverage.txt -covermode=atomic ./credentials/...

- name: Integration Test
run: test -z $SUB_ALICLOUD_ACCESS_KEY -a -z $SUB_ALICLOUD_SECRET_KEY || go test -v -timeout 120s ./integration/...
run: go test -v -timeout 120s ./integration/...
env:
SUB_ALICLOUD_ACCESS_KEY: ${{ secrets.SUB_ALICLOUD_ACCESS_KEY }}
SUB_ALICLOUD_SECRET_KEY: ${{ secrets.SUB_ALICLOUD_SECRET_KEY }}
ALICLOUD_ROLE_ARN: ${{ secrets.ALICLOUD_ROLE_ARN }}
ALICLOUD_ROLE_SESSION_NAME: ${{ secrets.ALICLOUD_ROLE_SESSION_NAME }}
ALICLOUD_ROLE_SESSION_EXPIRATION: ${{ secrets.ALICLOUD_ROLE_SESSION_EXPIRATION }}

- name: CodeCov
run: bash <(curl -s https://codecov.io/bash) -cF credentials-go
6 changes: 0 additions & 6 deletions credentials/oidc_credential.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,6 @@ func (r *OIDCCredential) updateCredential() (err error) {
request.QueryParams["RoleSessionName"] = r.RoleSessionName
request.QueryParams["Version"] = "2015-04-01"
request.QueryParams["SignatureNonce"] = utils.GetUUID()
if r.AccessKeyId != "" && r.AccessKeySecret != "" {
signature := utils.ShaHmac1(request.BuildStringToSign(), r.AccessKeySecret+"&")
request.QueryParams["Signature"] = signature
request.QueryParams["AccessKeyId"] = r.AccessKeyId
request.QueryParams["AccessKeySecret"] = r.AccessKeySecret
}
request.Headers["Host"] = request.Domain
request.Headers["Accept-Encoding"] = "identity"
request.Headers["content-type"] = "application/x-www-form-urlencoded"
Expand Down
36 changes: 36 additions & 0 deletions credentials/oidc_credential_provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package credentials

import (
"os"

"github.com/alibabacloud-go/tea/tea"
)

type oidcCredentialsProvider struct{}

var providerOIDC = new(oidcCredentialsProvider)

func newOidcCredentialsProvider() Provider {
return &oidcCredentialsProvider{}
}

func (p *oidcCredentialsProvider) resolve() (*Config, error) {
roleArn, ok1 := os.LookupEnv(ENVRoleArn)
oidcProviderArn, ok2 := os.LookupEnv(ENVOIDCProviderArn)
oidcTokenFilePath, ok3 := os.LookupEnv(ENVOIDCTokenFile)
if !ok1 || !ok2 || !ok3 {
return nil, nil
}

config := &Config{
Type: tea.String("oidc_role_arn"),
RoleArn: tea.String(roleArn),
OIDCProviderArn: tea.String(oidcProviderArn),
OIDCTokenFilePath: tea.String(oidcTokenFilePath),
}
roleSessionName, ok := os.LookupEnv(ENVRoleSessionName)
if ok {
config.RoleSessionName = tea.String(roleSessionName)
}
return config, nil
}
50 changes: 50 additions & 0 deletions credentials/oidc_credential_provider_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package credentials

import (
"os"
"testing"

"github.com/alibabacloud-go/tea/tea"
"github.com/stretchr/testify/assert"
)

func TestOidcCredentialsProvider(t *testing.T) {
p := newOidcCredentialsProvider()
roleArn := os.Getenv(ENVRoleArn)
oidcProviderArn := os.Getenv(ENVOIDCProviderArn)
oidcTokenFilePath := os.Getenv(ENVOIDCTokenFile)
roleSessionName := os.Getenv(ENVRoleSessionName)
os.Setenv(ENVRoleArn, "")
os.Setenv(ENVOIDCProviderArn, "")
os.Setenv(ENVOIDCTokenFile, "")
os.Setenv(ENVRoleSessionName, "")
defer func() {
os.Setenv(ENVRoleArn, roleArn)
os.Setenv(ENVOIDCProviderArn, oidcProviderArn)
os.Setenv(ENVOIDCTokenFile, oidcTokenFilePath)
os.Setenv(ENVRoleSessionName, roleSessionName)
}()
c, err := p.resolve()
assert.NotNil(t, c)
assert.Nil(t, err)

os.Setenv(ENVRoleArn, "roleArn")
os.Setenv(ENVOIDCProviderArn, "oidcProviderArn")
os.Setenv(ENVOIDCTokenFile, "oidcTokenFilePath")
os.Setenv(ENVRoleSessionName, "roleSessionName")
c, err = p.resolve()
assert.Nil(t, err)
assert.Equal(t, "roleArn", tea.StringValue(c.RoleArn))
assert.Equal(t, "oidcProviderArn", tea.StringValue(c.OIDCProviderArn))
assert.Equal(t, "oidcTokenFilePath", tea.StringValue(c.OIDCTokenFilePath))
assert.Equal(t, "roleSessionName", tea.StringValue(c.RoleSessionName))
assert.Equal(t, "oidc_role_arn", tea.StringValue(c.Type))

os.Unsetenv(ENVRoleArn)
os.Unsetenv(ENVOIDCProviderArn)
os.Unsetenv(ENVOIDCTokenFile)
os.Unsetenv(ENVRoleSessionName)
c, err = p.resolve()
assert.Nil(t, c)
assert.Nil(t, err)
}
4 changes: 4 additions & 0 deletions credentials/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ const (
ENVCredentialFile = "ALIBABA_CLOUD_CREDENTIALS_FILE"
ENVEcsMetadata = "ALIBABA_CLOUD_ECS_METADATA"
PATHCredentialFile = "~/.alibabacloud/credentials"
ENVRoleArn = "ALIBABA_CLOUD_ROLE_ARN"
ENVOIDCProviderArn = "ALIBABA_CLOUD_OIDC_PROVIDER_ARN"
ENVOIDCTokenFile = "ALIBABA_CLOUD_OIDC_TOKEN_FILE"
ENVRoleSessionName = "ALIBABA_CLOUD_ROLE_SESSION_NAME"
)

// Provider will be implemented When you want to customize the provider.
Expand Down
2 changes: 1 addition & 1 deletion credentials/provider_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ type providerChain struct {
Providers []Provider
}

var defaultproviders = []Provider{providerEnv, providerProfile, providerInstance}
var defaultproviders = []Provider{providerEnv, providerOIDC, providerProfile, providerInstance}
var defaultChain = newProviderChain(defaultproviders)

func newProviderChain(providers []Provider) Provider {
Expand Down
77 changes: 77 additions & 0 deletions credentials/provider_chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"os"
"testing"

"github.com/alibabacloud-go/tea/tea"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -44,3 +45,79 @@ func TestProviderChain(t *testing.T) {
assert.Nil(t, c)
assert.EqualError(t, err, "No credential found")
}

func TestDefaultChainNoCred(t *testing.T) {
accessKeyIdNew := os.Getenv(EnvVarAccessKeyIdNew)
accessKeyId := os.Getenv(EnvVarAccessKeyId)
accessKeySecret := os.Getenv(EnvVarAccessKeySecret)
ecsMetadata := os.Getenv(ENVEcsMetadata)
roleArn := os.Getenv(ENVRoleArn)
oidcProviderArn := os.Getenv(ENVOIDCProviderArn)
oidcTokenFilePath := os.Getenv(ENVOIDCTokenFile)
roleSessionName := os.Getenv(ENVRoleSessionName)
os.Unsetenv(EnvVarAccessKeyId)
os.Unsetenv(EnvVarAccessKeySecret)
os.Unsetenv(ENVCredentialFile)
os.Unsetenv(ENVEcsMetadata)
os.Unsetenv(ENVRoleArn)
os.Unsetenv(ENVOIDCProviderArn)
os.Unsetenv(ENVOIDCTokenFile)
os.Unsetenv(ENVRoleSessionName)
defer func() {
os.Setenv(EnvVarAccessKeyIdNew, accessKeyIdNew)
os.Setenv(EnvVarAccessKeyId, accessKeyId)
os.Setenv(EnvVarAccessKeySecret, accessKeySecret)
os.Setenv(ENVEcsMetadata, ecsMetadata)
os.Setenv(ENVRoleArn, roleArn)
os.Setenv(ENVOIDCProviderArn, oidcProviderArn)
os.Setenv(ENVOIDCTokenFile, oidcTokenFilePath)
os.Setenv(ENVRoleSessionName, roleSessionName)
}()

chain, err := defaultChain.resolve()
assert.Nil(t, chain)
assert.Equal(t, "No credential found", err.Error())
}

func TestDefaultChainHasCred(t *testing.T) {
accessKeyIdNew := os.Getenv(EnvVarAccessKeyIdNew)
accessKeyId := os.Getenv(EnvVarAccessKeyId)
accessKeySecret := os.Getenv(EnvVarAccessKeySecret)
os.Unsetenv(EnvVarAccessKeyId)
os.Unsetenv(EnvVarAccessKeySecret)
os.Unsetenv(ENVCredentialFile)

path, _ := os.Getwd()
oidcTokenFilePathVar := path + "/oidc_token"
roleArn := os.Getenv(ENVRoleArn)
oidcProviderArn := os.Getenv(ENVOIDCProviderArn)
oidcTokenFilePath := os.Getenv(ENVOIDCTokenFile)
roleSessionName := os.Getenv(ENVRoleSessionName)
os.Setenv(ENVRoleArn, "acs:ram::roleArn:role/roleArn")
os.Setenv(ENVOIDCProviderArn, "acs:ram::roleArn")
os.Setenv(ENVOIDCTokenFile, oidcTokenFilePathVar)
os.Setenv(ENVRoleSessionName, "roleSessionName")
defer func() {
os.Setenv(EnvVarAccessKeyIdNew, accessKeyIdNew)
os.Setenv(EnvVarAccessKeyId, accessKeyId)
os.Setenv(EnvVarAccessKeySecret, accessKeySecret)
os.Setenv(ENVRoleArn, roleArn)
os.Setenv(ENVOIDCProviderArn, oidcProviderArn)
os.Setenv(ENVOIDCTokenFile, oidcTokenFilePath)
os.Setenv(ENVRoleSessionName, roleSessionName)
}()

config, err := defaultChain.resolve()
assert.NotNil(t, config)
assert.Nil(t, err)
assert.Equal(t, "acs:ram::roleArn:role/roleArn", tea.StringValue(config.RoleArn))
assert.Equal(t, "acs:ram::roleArn", tea.StringValue(config.OIDCProviderArn))
assert.Equal(t, oidcTokenFilePathVar, tea.StringValue(config.OIDCTokenFilePath))
assert.Equal(t, "roleSessionName", tea.StringValue(config.RoleSessionName))
assert.Equal(t, "oidc_role_arn", tea.StringValue(config.Type))

cred, err := NewCredential(nil)
assert.Nil(t, err)
assert.NotNil(t, cred)
assert.Contains(t, "oidc_role_arn", tea.StringValue(cred.GetType()))
}
17 changes: 17 additions & 0 deletions integration/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,20 @@ func Test_Arn(t *testing.T) {
assert.Nil(t, err)
assert.NotNil(t, accesskey)
}

func Test_Oidc(t *testing.T) {
path, _ := os.Getwd()
oidcTokenFilePath := path + "../credentials/oidc_token"
config := &credentials.Config{
Type: tea.String("oidc_role_arn"),
RoleArn: tea.String("acs:ram::roleArn:role/roleArn"),
OIDCProviderArn: tea.String("acs:ram::roleArn"),
OIDCTokenFilePath: tea.String(oidcTokenFilePath),
}
cred, err := credentials.NewCredential(config)
assert.Nil(t, err)
assert.NotNil(t, cred)
_, err = cred.GetAccessKeyId()
assert.NotNil(t, err)
assert.Contains(t, err.Error(), "AuthenticationFail.OIDCToken.Invalid")
}

0 comments on commit 3bee676

Please sign in to comment.