Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mantle: overhaul aliyun auth #3147

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 26 additions & 35 deletions docs/mantle/credentials.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,45 +19,36 @@ kola spawn -p aws --aws-profile other_profile

## aliyun

`aliyun` reads the `~/.aliyun/config.json` file used by Aliyun's aliyun command-line tool.
It can be created using the `aliyun` command:
```
$ aliyun configure
```
To configure a different profile, use the `--profile` flag
```
$ aliyun configure --profile other_profile
```
The Access Key/Secret for the Aliyun SDK can be specified either
in a [credentials file](https://github.com/aliyun/alibaba-cloud-sdk-go/blob/master/docs/2-Client-EN.md#2-credentials-file)
or directly in [environment variables](https://github.com/aliyun/alibaba-cloud-sdk-go/blob/master/docs/2-Client-EN.md#1-environment-credentials)
as authentication input.

- credentials file
- place the file in `~/.alibabacloud/credentials`
- populate the `ALIBABA_CLOUD_CREDENTIALS_FILE` environment variable
with the path to the credentials file.
- environment variables
- populate the key in the `ALIBABA_CLOUD_ACCESS_KEY_ID` environment variable
- populate the secret in the `ALIBABA_CLOUD_ACCESS_KEY_SECRET` environment variable

Ironically, the `aliyun` CLI uses the slightly different
[environment variables](https://github.com/aliyun/aliyun-cli#support-for-environment-variables)
of `ALIBABACLOUD_ACCESS_KEY_ID` and `ALIBABACLOUD_ACCESS_KEY_SECRET`.


For mantle populate the credentials file and either place it at `~/.alibabacloud/credentials`
or populate the `ALIBABA_CLOUD_CREDENTIALS_FILE` environment variable.

The `~/.aliyun/config.json` file can also be populated manually:
```
{
"current": "",
"profiles": [
{
"name": "",
"mode": "AK",
"access_key_id": "ACCESS_KEY_ID",
"access_key_secret": "ACCESS_KEY_SECRET",
"sts_token": "",
"ram_role_name": "",
"ram_role_arn": "",
"ram_session_name": "",
"private_key": "",
"key_pair_name": "",
"expired_seconds": 0,
"verified": "",
"region_id": "eu-central-1",
"output_format": "json",
"language": "zh",
"site": "",
"retry_timeout": 0,
"retry_count": 0
}
]
}
[default]
type=access_key
access_key_id=ACCESS_KEY_ID
access_key_secret=ACCESS_KEY_SECRET
```

To configure a different profile than `default`, use the `--profile` flag.

## aws

`aws` reads the `~/.aws/credentials` file used by Amazon's aws command-line tool.
Expand Down
70 changes: 0 additions & 70 deletions mantle/auth/aliyun.go

This file was deleted.

5 changes: 1 addition & 4 deletions mantle/cmd/ore/aliyun/aliyun.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ package aliyun

import (
"fmt"
"os"

"github.com/coreos/pkg/capnslog"
"github.com/spf13/cobra"
Expand All @@ -38,9 +37,7 @@ var (
)

func init() {
defaultConfigPath := os.Getenv("ALIYUN_CONFIG_FILE")

Aliyun.PersistentFlags().StringVar(&options.ConfigPath, "config-file", defaultConfigPath, "config file (default \""+defaultConfigPath+"\")")
Aliyun.PersistentFlags().StringVar(&options.CredentialsFile, "credentials-file", "", "Use custom path for Aliyun credentials file")
Aliyun.PersistentFlags().StringVar(&options.Profile, "profile", "", "profile (default \"default\")")
Aliyun.PersistentFlags().StringVar(&options.Region, "region", "", "region")
cli.WrapPreRun(Aliyun, preflightCheck)
Expand Down
65 changes: 40 additions & 25 deletions mantle/platform/api/aliyun/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,17 @@ package aliyun
import (
"fmt"
"io"
"os"
"sort"
"time"

"github.com/coreos/mantle/auth"
"github.com/coreos/mantle/platform"
"github.com/coreos/mantle/util"
"github.com/coreos/pkg/capnslog"
"github.com/coreos/pkg/multierror"

"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials/provider"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
Expand All @@ -41,8 +43,11 @@ type Options struct {
// The aliyun region regional api calls should use
Region string

// Config file. Defaults to ~/.aliyun/config.json
ConfigPath string

// Path to an ALIBABA_CLOUD_CREDENTIALS_FILE
// https://github.com/aliyun/alibaba-cloud-sdk-go/blob/master/docs/2-Client-EN.md#2-credentials-file
CredentialsFile string

// The profile to use when resolving credentials, if applicable
Profile string

Expand All @@ -62,30 +67,40 @@ type API struct {
// standard credentials sources, including the environment and the profile
// configured in ~/.aliyun.
func New(opts *Options) (*API, error) {
profiles, err := auth.ReadAliyunConfig(opts.ConfigPath)
if err != nil {
return nil, fmt.Errorf("couldn't read aliyun config: %v", err)
}

if opts.Profile == "" {
opts.Profile = "default"
}

profile, ok := profiles[opts.Profile]
if !ok {
return nil, fmt.Errorf("no such profile %q", opts.Profile)
}

if opts.AccessKeyID == "" {
opts.AccessKeyID = profile.AccessKeyID
}

if opts.SecretKey == "" {
opts.SecretKey = profile.AccessKeySecret
}
// If the user didn't provide an access key and secret directly then try to pick up
// the credentials from the normal locations defined by the SDK
// https://github.com/aliyun/alibaba-cloud-sdk-go/blob/master/docs/2-Client-EN.md#default-credential-provider-chain
if opts.AccessKeyID == "" || opts.SecretKey == "" {

// If the user provided a path to a credential file then
// let's set it now the only supported way, which is with
// the ALIBABA_CLOUD_CREDENTIALS_FILE env var.
if opts.CredentialsFile != "" {
os.Setenv(provider.ENVCredentialFile, opts.CredentialsFile)
defer os.Unsetenv(provider.ENVCredentialFile)
}

if opts.Region == "" {
opts.Region = profile.Region
var p provider.Provider
if opts.Profile != "" {
// If the user specified a profile then they're
// using a credentials file with profiles in them.
p = provider.NewProfileProvider(opts.Profile)
} else {
// If not then they could be using environment variables
// so use the DefaultChain (includes env var provider)
p = provider.DefaultChain
}
credential, err := p.Resolve()
if err != nil {
return nil, fmt.Errorf("failed to detect aliyun auth credentials: %w", err)
}
keycred, ok := credential.(*credentials.AccessKeyCredential)
if !ok {
return nil, fmt.Errorf("failed to convert the credential to an AccessKeyCredential")
}
opts.AccessKeyID = keycred.AccessKeyId
opts.SecretKey = keycred.AccessKeySecret
}

ecs, err := ecs.NewClientWithAccessKey(opts.Region, opts.AccessKeyID, opts.SecretKey)
Expand Down
2 changes: 0 additions & 2 deletions src/cmd-ore-wrapper
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,6 @@ Each target has its own sub options. To access them us:
parser.add_argument("--build-artifact", "--build-if-missing",
action='store_true', default=default_build_artifact,
help="Build the artifact if missing")
parser.add_argument("--config", "--config-file",
help="ore configuration")
parser.add_argument("--force", action='store_true',
help="Force the operation if it has already happened")
parser.add_argument("--compress", action='store_true',
Expand Down
13 changes: 7 additions & 6 deletions src/cosalib/aliyun.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def aliyun_run_ore_replicate(build, args):

if not args.region:
args.region = subprocess.check_output([
'ore', f'--config-file={args.config}' if args.config else '',
'ore', f'--credentials-file={args.credentials_file}' if args.credentials_file else '',
'aliyun', 'list-regions'
]).decode().strip().split()
log.info(("default: replicating to all regions. If this is not "
Expand Down Expand Up @@ -65,8 +65,8 @@ def aliyun_run_ore_replicate(build, args):
'--wait-for-ready'
]

if args.config:
ore_args.extend(['--config-file', args.config])
if args.credentials_file:
ore_args.extend(['--credentials-file', args.credentials_file])

upload_failed_in_region = None

Expand Down Expand Up @@ -115,8 +115,8 @@ def make_public(build, args):
'aliyun', 'visibility', '--public'
]

if args.config:
make_public_args.extend(['--config-file', args.config])
if args.credentials_file:
make_public_args.extend(['--credentials-file', args.credentials_file])

# build out a list of region:image pairs to pass to `ore aliyun visibility`
region_image_pairs = []
Expand Down Expand Up @@ -157,7 +157,7 @@ def aliyun_run_ore(build, args):
raise Exception("Must supply OSS bucket when uploading")

ore_args.extend([
f'--config-file={args.config}' if args.config else '',
f'--credentails-file={args.credentials_file}' if args.credentials_file else '',
'aliyun', 'create-image',
'--region', region,
'--bucket', args.bucket,
Expand Down Expand Up @@ -187,6 +187,7 @@ def aliyun_run_ore(build, args):

def aliyun_cli(parser):
parser.add_argument("--bucket", help="OSS Bucket")
parser.add_argument("--credentials-file", help="Credentials file to use")
parser.add_argument("--name-suffix", help="Suffix for uploaded image name")
parser.add_argument("--public", action="store_true", help="Mark images as publicly available")
return parser