Skip to content

Commit

Permalink
Update Kanctl to Create profile with secret CredentialType (#369)
Browse files Browse the repository at this point in the history
* Create profile with secret creds type

* Fix CI failures after rebase with master
  • Loading branch information
SupriyaKasten authored and mergify[bot] committed Nov 5, 2019
1 parent e90c50d commit a5f0bd5
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 34 deletions.
4 changes: 2 additions & 2 deletions pkg/apis/cr/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,8 @@ const (
// Credential
type Credential struct {
Type CredentialType `json:"type"`
KeyPair *KeyPair `json:"keyPair"`
Secret *ObjectReference `json:"secret"`
KeyPair *KeyPair `json:"keyPair,omitempty"`
Secret *ObjectReference `json:"secret,omitempty"`
}

// KeyPair
Expand Down
53 changes: 38 additions & 15 deletions pkg/kanctl/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (

"github.com/kanisterio/kanister/pkg/apis/cr/v1alpha1"
"github.com/kanisterio/kanister/pkg/client/clientset/versioned"
"github.com/kanisterio/kanister/pkg/secrets"
"github.com/kanisterio/kanister/pkg/validate"
)

Expand All @@ -43,13 +44,15 @@ const (
regionFlag = "region"
awsAccessKeyFlag = "access-key"
awsSecretKeyFlag = "secret-key"
awsRoleFlag = "role"
gcpProjectIDFlag = "project-id"
gcpServiceKeyFlag = "service-key"
AzureStorageAccountFlag = "storage-account"
AzureStorageKeyFlag = "storage-key"

idField = "access_key_id"
secretField = "secret_access_key"
roleField = "role" // required only for AWS IAM role
skipSSLVerifyFlag = "skip-SSL-verification"

schemaValidation = "Validate Profile schema"
Expand Down Expand Up @@ -101,6 +104,7 @@ func newS3CompliantProfileCmd() *cobra.Command {

cmd.Flags().StringP(awsAccessKeyFlag, "a", "", "access key of the s3 compliant bucket")
cmd.Flags().StringP(awsSecretKeyFlag, "s", "", "secret key of the s3 compliant bucket")
cmd.Flags().StringP(awsRoleFlag, "R", "", "AWS IAM role")

cmd.MarkFlagRequired(awsAccessKeyFlag)
cmd.MarkFlagRequired(awsSecretKeyFlag)
Expand Down Expand Up @@ -163,7 +167,7 @@ func createNewProfile(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
profile := constructProfile(lP, secret)
profile := constructProfile(lP, secret, string(secret.StringData[roleField]))
if dryRun {
// Just perform schema validation and print YAML
if err := validate.ProfileSchema(profile); err != nil {
Expand Down Expand Up @@ -229,7 +233,29 @@ func getLocationParams(cmd *cobra.Command) (*locationParams, error) {
}, nil
}

func constructProfile(lP *locationParams, secret *v1.Secret) *v1alpha1.Profile {
func constructProfile(lP *locationParams, secret *v1.Secret, role string) *v1alpha1.Profile {
var creds v1alpha1.Credential
if role == "" {
creds = v1alpha1.Credential{
Type: v1alpha1.CredentialTypeKeyPair,
KeyPair: &v1alpha1.KeyPair{
IDField: idField,
SecretField: secretField,
Secret: v1alpha1.ObjectReference{
Name: secret.GetName(),
Namespace: secret.GetNamespace(),
},
},
}
} else {
creds = v1alpha1.Credential{
Type: v1alpha1.CredentialTypeSecret,
Secret: &v1alpha1.ObjectReference{
Name: secret.GetName(),
Namespace: secret.GetNamespace(),
},
}
}
return &v1alpha1.Profile{
ObjectMeta: metav1.ObjectMeta{
Namespace: lP.namespace,
Expand All @@ -242,30 +268,23 @@ func constructProfile(lP *locationParams, secret *v1.Secret) *v1alpha1.Profile {
Prefix: lP.prefix,
Region: lP.region,
},
Credential: v1alpha1.Credential{
Type: v1alpha1.CredentialTypeKeyPair,
KeyPair: &v1alpha1.KeyPair{
IDField: idField,
SecretField: secretField,
Secret: v1alpha1.ObjectReference{
Name: secret.GetName(),
Namespace: secret.GetNamespace(),
},
},
},
Credential: creds,
SkipSSLVerify: lP.skipSSLVerify,
}
}

func constructSecret(ctx context.Context, lP *locationParams, cmd *cobra.Command) (*v1.Secret, error) {
data := make(map[string]string, 2)
var roleKey string
secretname := ""
switch lP.locationType {
case v1alpha1.LocationTypeS3Compliant:
accessKey, _ := cmd.Flags().GetString(awsAccessKeyFlag)
secretKey, _ := cmd.Flags().GetString(awsSecretKeyFlag)
roleKey, _ = cmd.Flags().GetString(awsRoleFlag)
data[idField] = accessKey
data[secretField] = secretKey
data[roleField] = roleKey
secretname = "s3"
case v1alpha1.LocationTypeGCS:
projectID, _ := cmd.Flags().GetString(gcpProjectIDFlag)
Expand All @@ -284,13 +303,17 @@ func constructSecret(ctx context.Context, lP *locationParams, cmd *cobra.Command
data[secretField] = storageKey
secretname = "azure"
}
return &v1.Secret{
secret := &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf(secretFormat, secretname, randString(6)),
Namespace: lP.namespace,
},
StringData: data,
}, nil
}
if roleKey != "" {
secret.Type = v1.SecretType(secrets.AWSSecretType)
}
return secret, nil
}

func createSecret(ctx context.Context, s *v1.Secret, cli kubernetes.Interface) (*v1.Secret, error) {
Expand Down
55 changes: 38 additions & 17 deletions pkg/validate/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
crv1alpha1 "github.com/kanisterio/kanister/pkg/apis/cr/v1alpha1"
"github.com/kanisterio/kanister/pkg/objectstore"
"github.com/kanisterio/kanister/pkg/param"
"github.com/kanisterio/kanister/pkg/secrets"
)

// ActionSet function validates the ActionSet and returns an error if it is invalid.
Expand Down Expand Up @@ -198,7 +199,7 @@ func ProfileBucket(ctx context.Context, p *crv1alpha1.Profile, cli kubernetes.In
return errorf("unknown or unsupported location type '%s'", p.Location.Type)
}
pc := objectstore.ProviderConfig{Type: pType}
secret, err := osSecretFromProfile(pType, p, cli)
secret, err := osSecretFromProfile(ctx, pType, p, cli)
if err != nil {
return err
}
Expand Down Expand Up @@ -227,7 +228,7 @@ func ReadAccess(ctx context.Context, p *crv1alpha1.Profile, cli kubernetes.Inter
default:
return errorf("unknown or unsupported location type '%s'", p.Location.Type)
}
secret, err = osSecretFromProfile(pType, p, cli)
secret, err = osSecretFromProfile(ctx, pType, p, cli)
if err != nil {
return err
}
Expand Down Expand Up @@ -264,7 +265,7 @@ func WriteAccess(ctx context.Context, p *crv1alpha1.Profile, cli kubernetes.Inte
default:
return errorf("unknown or unsupported location type '%s'", p.Location.Type)
}
secret, err = osSecretFromProfile(pType, p, cli)
secret, err = osSecretFromProfile(ctx, pType, p, cli)
if err != nil {
return err
}
Expand Down Expand Up @@ -293,24 +294,44 @@ func WriteAccess(ctx context.Context, p *crv1alpha1.Profile, cli kubernetes.Inte
return nil
}

func osSecretFromProfile(pType objectstore.ProviderType, p *crv1alpha1.Profile, cli kubernetes.Interface) (*objectstore.Secret, error) {
func osSecretFromProfile(ctx context.Context, pType objectstore.ProviderType, p *crv1alpha1.Profile, cli kubernetes.Interface) (*objectstore.Secret, error) {
var key, value []byte
var ok bool
secret := &objectstore.Secret{}
kp := p.Credential.KeyPair
if kp == nil {
return nil, errorf("invalid credentials kv cannot be nil")
}
s, err := cli.CoreV1().Secrets(kp.Secret.Namespace).Get(kp.Secret.Name, metav1.GetOptions{})
if err != nil {
return nil, errorf("could not fetch the secret specified in credential")
}
if key, ok = s.Data[kp.IDField]; !ok {
return nil, errorf("Key '%s' not found in secret '%s:%s'", kp.IDField, s.GetNamespace(), s.GetName())
}
if value, ok = s.Data[kp.SecretField]; !ok {
return nil, errorf("Value '%s' not found in secret '%s:%s'", kp.SecretField, s.GetNamespace(), s.GetName())
switch p.Credential.Type {
case crv1alpha1.CredentialTypeKeyPair:
kp := p.Credential.KeyPair
if kp == nil {
return nil, errorf("Invalid credentials kv cannot be nil")
}
s, err := cli.CoreV1().Secrets(kp.Secret.Namespace).Get(kp.Secret.Name, metav1.GetOptions{})
if err != nil {
return nil, errorf("Could not fetch the secret specified in credential")
}
if key, ok = s.Data[kp.IDField]; !ok {
return nil, errorf("Key '%s' not found in secret '%s:%s'", kp.IDField, s.GetNamespace(), s.GetName())
}
if value, ok = s.Data[kp.SecretField]; !ok {
return nil, errorf("Value '%s' not found in secret '%s:%s'", kp.SecretField, s.GetNamespace(), s.GetName())
}
case crv1alpha1.CredentialTypeSecret:
s, err := cli.CoreV1().Secrets(p.Credential.Secret.Namespace).Get(p.Credential.Secret.Name, metav1.GetOptions{})
if err != nil {
return nil, errorf("Could not fetch the secret specified in credential")
}
creds, err := secrets.ExtractAWSCredentials(ctx, s)
if err != nil {
return nil, err
}
secret.Type = objectstore.SecretTypeAwsAccessKey
secret.Aws = &objectstore.SecretAws{
AccessKeyID: creds.AccessKeyID,
SecretAccessKey: creds.SecretAccessKey,
SessionToken: creds.SessionToken,
}
return secret, nil
}

switch pType {
case objectstore.ProviderTypeS3:
secret.Type = objectstore.SecretTypeAwsAccessKey
Expand Down

0 comments on commit a5f0bd5

Please sign in to comment.