gcp.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. package integrations
  2. import (
  3. "context"
  4. "encoding/json"
  5. "golang.org/x/oauth2/google"
  6. "gorm.io/gorm"
  7. )
  8. // GCPIntegration is an auth mechanism that uses a GCP service account to
  9. // authenticate
  10. type GCPIntegration struct {
  11. gorm.Model
  12. // The id of the user that linked this auth mechanism
  13. UserID uint `json:"user_id"`
  14. // The project that this integration belongs to
  15. ProjectID uint `json:"project_id"`
  16. // The GCP project id where the service account for this auth mechanism persists
  17. GCPProjectID string `json:"gcp_project_id"`
  18. // The GCP user email that linked this service account
  19. GCPUserEmail string `json:"gcp-user-email"`
  20. // The GCP region, which may or may not be used by the integration
  21. GCPRegion string `json:"gcp_region"`
  22. // ------------------------------------------------------------------
  23. // All fields encrypted before storage.
  24. // ------------------------------------------------------------------
  25. // KeyData for a service account for GCP connectors
  26. GCPKeyData []byte `json:"gcp_key_data"`
  27. }
  28. // GCPIntegrationExternal is a GCPIntegration to be shared over REST
  29. type GCPIntegrationExternal struct {
  30. ID uint `json:"id"`
  31. // The id of the user that linked this auth mechanism
  32. UserID uint `json:"user_id"`
  33. // The project that this integration belongs to
  34. ProjectID uint `json:"project_id"`
  35. // The GCP project id where the service account for this auth mechanism persists
  36. GCPProjectID string `json:"gcp-project-id"`
  37. // The GCP user email that linked this service account
  38. GCPUserEmail string `json:"gcp-user-email"`
  39. }
  40. // Externalize generates an external KubeIntegration to be shared over REST
  41. func (g *GCPIntegration) Externalize() *GCPIntegrationExternal {
  42. return &GCPIntegrationExternal{
  43. ID: g.ID,
  44. UserID: g.UserID,
  45. ProjectID: g.ProjectID,
  46. GCPProjectID: g.GCPProjectID,
  47. GCPUserEmail: g.GCPUserEmail,
  48. }
  49. }
  50. // ToProjectIntegration converts a gcp integration to a project integration
  51. func (g *GCPIntegration) ToProjectIntegration(
  52. category string,
  53. service IntegrationService,
  54. ) *ProjectIntegration {
  55. return &ProjectIntegration{
  56. ID: g.ID,
  57. ProjectID: g.ProjectID,
  58. AuthMechanism: "gcp",
  59. Category: category,
  60. Service: service,
  61. }
  62. }
  63. // GetBearerToken retrieves a bearer token for a GCP account
  64. func (g *GCPIntegration) GetBearerToken(
  65. getTokenCache GetTokenCacheFunc,
  66. setTokenCache SetTokenCacheFunc,
  67. scopes ...string,
  68. ) (string, error) {
  69. cache, err := getTokenCache()
  70. // check the token cache for a non-expired token
  71. if cache != nil {
  72. if tok := cache.Token; err == nil && !cache.IsExpired() && len(tok) > 0 {
  73. return string(tok), nil
  74. }
  75. }
  76. creds, err := google.CredentialsFromJSON(
  77. context.Background(),
  78. g.GCPKeyData,
  79. scopes...,
  80. )
  81. if err != nil {
  82. return "", err
  83. }
  84. tok, err := creds.TokenSource.Token()
  85. if err != nil {
  86. return "", err
  87. }
  88. // update the token cache
  89. setTokenCache(tok.AccessToken, tok.Expiry)
  90. return tok.AccessToken, nil
  91. }
  92. // credentialsFile is the unmarshalled representation of a GCP credentials file.
  93. // Source; golang.org/x/oauth2/google
  94. type credentialsFile struct {
  95. Type string `json:"type"` // serviceAccountKey or userCredentialsKey
  96. // Service Account fields
  97. ClientEmail string `json:"client_email"`
  98. PrivateKeyID string `json:"private_key_id"`
  99. PrivateKey string `json:"private_key"`
  100. TokenURL string `json:"token_uri"`
  101. ProjectID string `json:"project_id"`
  102. // User Credential fields
  103. // (These typically come from gcloud auth.)
  104. ClientSecret string `json:"client_secret"`
  105. ClientID string `json:"client_id"`
  106. RefreshToken string `json:"refresh_token"`
  107. // External Account fields
  108. Audience string `json:"audience"`
  109. SubjectTokenType string `json:"subject_token_type"`
  110. TokenURLExternal string `json:"token_url"`
  111. TokenInfoURL string `json:"token_info_url"`
  112. ServiceAccountImpersonationURL string `json:"service_account_impersonation_url"`
  113. // CredentialSource externalaccount.CredentialSource `json:"credential_source"`
  114. QuotaProjectID string `json:"quota_project_id"`
  115. }
  116. func GCPProjectIDFromJSON(jsonData []byte) (string, error) {
  117. var f credentialsFile
  118. if err := json.Unmarshal(jsonData, &f); err != nil {
  119. return "", err
  120. }
  121. return f.ProjectID, nil
  122. }