gcp.go 3.4 KB

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