2
0

aws.go 3.6 KB

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