sigs.k8s.io/cluster-api-provider-aws@v1.5.5/pkg/cloud/identity/identity.go (about)

     1  /*
     2  Copyright 2021 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  	http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package identity
    18  
    19  import (
    20  	"bytes"
    21  	"crypto/sha256"
    22  	"encoding/gob"
    23  	"time"
    24  
    25  	"github.com/aws/aws-sdk-go/aws"
    26  	"github.com/aws/aws-sdk-go/aws/credentials"
    27  	"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
    28  	"github.com/aws/aws-sdk-go/aws/session"
    29  	"github.com/aws/aws-sdk-go/service/sts/stsiface"
    30  	"github.com/go-logr/logr"
    31  	corev1 "k8s.io/api/core/v1"
    32  
    33  	infrav1 "sigs.k8s.io/cluster-api-provider-aws/api/v1beta1"
    34  )
    35  
    36  // AWSPrincipalTypeProvider defines the interface for AWS Principal Type Provider.
    37  type AWSPrincipalTypeProvider interface {
    38  	credentials.Provider
    39  	// Hash returns a unique hash of the data forming the credentials
    40  	// for this Principal
    41  	Hash() (string, error)
    42  	Name() string
    43  }
    44  
    45  // NewAWSStaticPrincipalTypeProvider will create a new AWSStaticPrincipalTypeProvider from a given AWSClusterStaticIdentity.
    46  func NewAWSStaticPrincipalTypeProvider(identity *infrav1.AWSClusterStaticIdentity, secret *corev1.Secret) *AWSStaticPrincipalTypeProvider {
    47  	accessKeyID := string(secret.Data["AccessKeyID"])
    48  	secretAccessKey := string(secret.Data["SecretAccessKey"])
    49  	sessionToken := string(secret.Data["SessionToken"])
    50  
    51  	return &AWSStaticPrincipalTypeProvider{
    52  		Principal:       identity,
    53  		credentials:     credentials.NewStaticCredentials(accessKeyID, secretAccessKey, sessionToken),
    54  		AccessKeyID:     accessKeyID,
    55  		SecretAccessKey: secretAccessKey,
    56  		SessionToken:    sessionToken,
    57  	}
    58  }
    59  
    60  // GetAssumeRoleCredentials will return the Credentials of a given AWSRolePrincipalTypeProvider.
    61  func GetAssumeRoleCredentials(roleIdentityProvider *AWSRolePrincipalTypeProvider, awsConfig *aws.Config) *credentials.Credentials {
    62  	sess := session.Must(session.NewSession(awsConfig))
    63  
    64  	creds := stscreds.NewCredentials(sess, roleIdentityProvider.Principal.Spec.RoleArn, func(p *stscreds.AssumeRoleProvider) {
    65  		if roleIdentityProvider.Principal.Spec.ExternalID != "" {
    66  			p.ExternalID = aws.String(roleIdentityProvider.Principal.Spec.ExternalID)
    67  		}
    68  		p.RoleSessionName = roleIdentityProvider.Principal.Spec.SessionName
    69  		if roleIdentityProvider.Principal.Spec.InlinePolicy != "" {
    70  			p.Policy = aws.String(roleIdentityProvider.Principal.Spec.InlinePolicy)
    71  		}
    72  		p.Duration = time.Duration(roleIdentityProvider.Principal.Spec.DurationSeconds) * time.Second
    73  		// For testing
    74  		if roleIdentityProvider.stsClient != nil {
    75  			p.Client = roleIdentityProvider.stsClient
    76  		}
    77  	})
    78  	return creds
    79  }
    80  
    81  // NewAWSRolePrincipalTypeProvider will create a new AWSRolePrincipalTypeProvider from an AWSClusterRoleIdentity.
    82  func NewAWSRolePrincipalTypeProvider(identity *infrav1.AWSClusterRoleIdentity, sourceProvider *AWSPrincipalTypeProvider, log logr.Logger) *AWSRolePrincipalTypeProvider {
    83  	return &AWSRolePrincipalTypeProvider{
    84  		credentials:    nil,
    85  		stsClient:      nil,
    86  		Principal:      identity,
    87  		sourceProvider: sourceProvider,
    88  		log:            log.WithName("AWSRolePrincipalTypeProvider"),
    89  	}
    90  }
    91  
    92  // AWSStaticPrincipalTypeProvider defines the specs for a static AWSPrincipalTypeProvider.
    93  type AWSStaticPrincipalTypeProvider struct {
    94  	Principal   *infrav1.AWSClusterStaticIdentity
    95  	credentials *credentials.Credentials
    96  	// these are for tests :/
    97  	AccessKeyID     string
    98  	SecretAccessKey string
    99  	SessionToken    string
   100  }
   101  
   102  // Hash returns the byte encoded AWSStaticPrincipalTypeProvider.
   103  func (p *AWSStaticPrincipalTypeProvider) Hash() (string, error) {
   104  	var roleIdentityValue bytes.Buffer
   105  	err := gob.NewEncoder(&roleIdentityValue).Encode(p)
   106  	if err != nil {
   107  		return "", err
   108  	}
   109  	hash := sha256.New()
   110  	return string(hash.Sum(roleIdentityValue.Bytes())), nil
   111  }
   112  
   113  // Retrieve returns the credential values for the AWSStaticPrincipalTypeProvider.
   114  func (p *AWSStaticPrincipalTypeProvider) Retrieve() (credentials.Value, error) {
   115  	return p.credentials.Get()
   116  }
   117  
   118  // Name returns the name of the AWSStaticPrincipalTypeProvider.
   119  func (p *AWSStaticPrincipalTypeProvider) Name() string {
   120  	return p.Principal.Name
   121  }
   122  
   123  // IsExpired checks the expiration state of the AWSStaticPrincipalTypeProvider.
   124  func (p *AWSStaticPrincipalTypeProvider) IsExpired() bool {
   125  	return p.credentials.IsExpired()
   126  }
   127  
   128  // AWSRolePrincipalTypeProvider defines the specs for a AWSPrincipalTypeProvider with a role.
   129  type AWSRolePrincipalTypeProvider struct {
   130  	Principal      *infrav1.AWSClusterRoleIdentity
   131  	credentials    *credentials.Credentials
   132  	sourceProvider *AWSPrincipalTypeProvider
   133  	log            logr.Logger
   134  	stsClient      stsiface.STSAPI
   135  }
   136  
   137  // Hash returns the byte encoded AWSRolePrincipalTypeProvider.
   138  func (p *AWSRolePrincipalTypeProvider) Hash() (string, error) {
   139  	var roleIdentityValue bytes.Buffer
   140  	err := gob.NewEncoder(&roleIdentityValue).Encode(p)
   141  	if err != nil {
   142  		return "", err
   143  	}
   144  	hash := sha256.New()
   145  	return string(hash.Sum(roleIdentityValue.Bytes())), nil
   146  }
   147  
   148  // Name returns the name of the AWSRolePrincipalTypeProvider.
   149  func (p *AWSRolePrincipalTypeProvider) Name() string {
   150  	return p.Principal.Name
   151  }
   152  
   153  // Retrieve returns the credential values for the AWSRolePrincipalTypeProvider.
   154  func (p *AWSRolePrincipalTypeProvider) Retrieve() (credentials.Value, error) {
   155  	if p.credentials == nil || p.IsExpired() {
   156  		awsConfig := aws.NewConfig()
   157  		if p.sourceProvider != nil {
   158  			sourceCreds, err := (*p.sourceProvider).Retrieve()
   159  			if err != nil {
   160  				return credentials.Value{}, err
   161  			}
   162  			awsConfig = awsConfig.WithCredentials(credentials.NewStaticCredentialsFromCreds(sourceCreds))
   163  		}
   164  
   165  		creds := GetAssumeRoleCredentials(p, awsConfig)
   166  		// Update credentials
   167  		p.credentials = creds
   168  	}
   169  	return p.credentials.Get()
   170  }
   171  
   172  // IsExpired checks the expiration state of the AWSRolePrincipalTypeProvider.
   173  func (p *AWSRolePrincipalTypeProvider) IsExpired() bool {
   174  	return p.credentials.IsExpired()
   175  }