authorizer.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. package gcp
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "github.com/opencost/opencost/pkg/cloud"
  6. "google.golang.org/api/option"
  7. )
  8. const ServiceAccountKeyAuthorizerType = "GCPServiceAccountKey"
  9. const WorkloadIdentityAuthorizerType = "GCPWorkloadIdentity"
  10. // Authorizer provide a []option.ClientOption which is used in when creating clients in the GCP SDK
  11. type Authorizer interface {
  12. cloud.Authorizer
  13. CreateGCPClientOptions() ([]option.ClientOption, error)
  14. }
  15. // SelectAuthorizerByType is an implementation of AuthorizerSelectorFn and acts as a register for Authorizer types
  16. func SelectAuthorizerByType(typeStr string) (Authorizer, error) {
  17. switch typeStr {
  18. case ServiceAccountKeyAuthorizerType:
  19. return &ServiceAccountKey{}, nil
  20. case WorkloadIdentityAuthorizerType:
  21. return &WorkloadIdentity{}, nil
  22. default:
  23. return nil, fmt.Errorf("GCP: provider authorizer type '%s' is not valid", typeStr)
  24. }
  25. }
  26. type ServiceAccountKey struct {
  27. Key map[string]string `json:"key"`
  28. }
  29. // MarshalJSON custom json marshalling functions, sets properties as tagged in struct and sets the authorizer type property
  30. func (gkc *ServiceAccountKey) MarshalJSON() ([]byte, error) {
  31. fmap := make(map[string]any, 2)
  32. fmap[cloud.AuthorizerTypeProperty] = ServiceAccountKeyAuthorizerType
  33. fmap["key"] = gkc.Key
  34. return json.Marshal(fmap)
  35. }
  36. func (gkc *ServiceAccountKey) Validate() error {
  37. if gkc.Key == nil || len(gkc.Key) == 0 {
  38. return fmt.Errorf("ServiceAccountKey: missing Key")
  39. }
  40. return nil
  41. }
  42. func (gkc *ServiceAccountKey) Equals(config cloud.Config) bool {
  43. if config == nil {
  44. return false
  45. }
  46. thatConfig, ok := config.(*ServiceAccountKey)
  47. if !ok {
  48. return false
  49. }
  50. if len(gkc.Key) != len(thatConfig.Key) {
  51. return false
  52. }
  53. for k, v := range gkc.Key {
  54. if thatConfig.Key[k] != v {
  55. return false
  56. }
  57. }
  58. return true
  59. }
  60. func (gkc *ServiceAccountKey) Sanitize() cloud.Config {
  61. redactedMap := make(map[string]string, len(gkc.Key))
  62. for key := range gkc.Key {
  63. redactedMap[key] = cloud.Redacted
  64. }
  65. return &ServiceAccountKey{
  66. Key: redactedMap,
  67. }
  68. }
  69. func (gkc *ServiceAccountKey) CreateGCPClientOptions() ([]option.ClientOption, error) {
  70. err := gkc.Validate()
  71. if err != nil {
  72. return nil, err
  73. }
  74. b, err := json.Marshal(gkc.Key)
  75. if err != nil {
  76. return nil, fmt.Errorf("Key: failed to marshal Key: %s", err.Error())
  77. }
  78. clientOption := option.WithCredentialsJSON(b)
  79. // The creation of the BigQuery Client is where FAILED_CONNECTION CloudConnectionStatus is recorded for GCP
  80. return []option.ClientOption{clientOption}, nil
  81. }
  82. // WorkloadIdentity passes an empty slice of client options which causes the GCP SDK to check for the workload identity in the environment
  83. type WorkloadIdentity struct{}
  84. // MarshalJSON custom json marshalling functions, sets properties as tagged in struct and sets the authorizer type property
  85. func (wi *WorkloadIdentity) MarshalJSON() ([]byte, error) {
  86. fmap := make(map[string]any, 1)
  87. fmap[cloud.AuthorizerTypeProperty] = WorkloadIdentityAuthorizerType
  88. return json.Marshal(fmap)
  89. }
  90. func (wi *WorkloadIdentity) Validate() error {
  91. return nil
  92. }
  93. func (wi *WorkloadIdentity) Equals(config cloud.Config) bool {
  94. if config == nil {
  95. return false
  96. }
  97. _, ok := config.(*WorkloadIdentity)
  98. if !ok {
  99. return false
  100. }
  101. return true
  102. }
  103. func (wi *WorkloadIdentity) Sanitize() cloud.Config {
  104. return &WorkloadIdentity{}
  105. }
  106. func (wi *WorkloadIdentity) CreateGCPClientOptions() ([]option.ClientOption, error) {
  107. return []option.ClientOption{}, nil
  108. }