aws.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. package integrations
  2. import (
  3. "fmt"
  4. "gorm.io/gorm"
  5. "github.com/aws/aws-sdk-go/aws"
  6. "github.com/aws/aws-sdk-go/service/sts"
  7. "github.com/aws/aws-sdk-go/aws/credentials"
  8. "github.com/aws/aws-sdk-go/aws/session"
  9. "github.com/porter-dev/porter/api/types"
  10. "sigs.k8s.io/aws-iam-authenticator/pkg/token"
  11. )
  12. // AWSIntegration is an auth mechanism that uses a AWS IAM user to
  13. // authenticate
  14. type AWSIntegration struct {
  15. gorm.Model
  16. // The id of the user that linked this auth mechanism
  17. UserID uint `json:"user_id"`
  18. // The project that this integration belongs to
  19. ProjectID uint `json:"project_id"`
  20. // The AWS arn this is integration is linked to
  21. AWSArn string `json:"aws_arn"`
  22. // The optional AWS region (required by some session configurations)
  23. AWSRegion string `json:"aws_region"`
  24. // The assumed role ARN to use for sessions
  25. AWSAssumeRoleArn string
  26. // ------------------------------------------------------------------
  27. // All fields encrypted before storage.
  28. // ------------------------------------------------------------------
  29. // The AWS cluster ID
  30. // See https://github.com/kubernetes-sigs/aws-iam-authenticator#what-is-a-cluster-id
  31. AWSClusterID []byte `json:"aws_cluster_id"`
  32. // The AWS access key for this IAM user
  33. AWSAccessKeyID []byte `json:"aws_access_key_id"`
  34. // The AWS secret key for this IAM user
  35. AWSSecretAccessKey []byte `json:"aws_secret_access_key"`
  36. // An optional session token, if the user is assuming a role
  37. AWSSessionToken []byte `json:"aws_session_token"`
  38. }
  39. func (a *AWSIntegration) ToAWSIntegrationType() *types.AWSIntegration {
  40. return &types.AWSIntegration{
  41. CreatedAt: a.CreatedAt,
  42. ID: a.ID,
  43. UserID: a.UserID,
  44. ProjectID: a.ProjectID,
  45. AWSArn: a.AWSArn,
  46. }
  47. }
  48. // GetSession retrieves an AWS session to use based on the access key and secret
  49. // access key
  50. func (a *AWSIntegration) GetSession() (*session.Session, error) {
  51. awsConf := &aws.Config{
  52. Credentials: credentials.NewStaticCredentials(
  53. string(a.AWSAccessKeyID),
  54. string(a.AWSSecretAccessKey),
  55. string(a.AWSSessionToken),
  56. ),
  57. }
  58. if a.AWSRegion != "" {
  59. awsConf.Region = &a.AWSRegion
  60. }
  61. return session.NewSessionWithOptions(session.Options{
  62. SharedConfigState: session.SharedConfigEnable,
  63. Config: *awsConf,
  64. })
  65. }
  66. // PopulateAWSArn uses the access key/secret to get the caller identity, and
  67. // attaches it to the AWS integration
  68. func (a *AWSIntegration) PopulateAWSArn() error {
  69. sess, err := a.GetSession()
  70. if err != nil {
  71. return err
  72. }
  73. svc := sts.New(sess)
  74. result, err := svc.GetCallerIdentity(&sts.GetCallerIdentityInput{})
  75. if err != nil {
  76. return err
  77. }
  78. a.AWSArn = *result.Arn
  79. return nil
  80. }
  81. // GetBearerToken retrieves a bearer token for an AWS account
  82. func (a *AWSIntegration) GetBearerToken(
  83. getTokenCache GetTokenCacheFunc,
  84. setTokenCache SetTokenCacheFunc,
  85. clusterID string,
  86. shouldClusterIdOverride bool,
  87. ) (string, error) {
  88. cache, err := getTokenCache()
  89. // check the token cache for a non-expired token
  90. if cache != nil {
  91. if tok := cache.Token; err == nil && !cache.IsExpired() && len(tok) > 0 {
  92. return string(tok), nil
  93. }
  94. }
  95. generator, err := token.NewGenerator(false, false)
  96. if err != nil {
  97. return "", err
  98. }
  99. sess, err := a.GetSession()
  100. if err != nil {
  101. return "", err
  102. }
  103. var validClusterId string
  104. if shouldClusterIdOverride {
  105. validClusterId = clusterID
  106. } else {
  107. validClusterId = string(a.AWSClusterID)
  108. if validClusterId == "" {
  109. validClusterId = clusterID
  110. }
  111. }
  112. fmt.Printf("assumerolearn: %s\n", a.AWSAssumeRoleArn)
  113. tok, err := generator.GetWithOptions(&token.GetTokenOptions{
  114. AssumeRoleARN: a.AWSAssumeRoleArn,
  115. Session: sess,
  116. ClusterID: validClusterId,
  117. })
  118. if err != nil {
  119. return "", err
  120. }
  121. setTokenCache(tok.Token, tok.Expiration)
  122. return tok.Token, nil
  123. }