aws.go 4.0 KB

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