authorizer.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. package azure
  2. import (
  3. "fmt"
  4. "github.com/Azure/azure-sdk-for-go/sdk/azcore"
  5. "github.com/Azure/azure-sdk-for-go/sdk/azidentity"
  6. "github.com/opencost/opencost/core/pkg/util/json"
  7. "github.com/opencost/opencost/pkg/cloud"
  8. )
  9. const (
  10. DefaultCredentialAuthorizerType = "AzureDefaultCredential"
  11. ClientSecretCredentialType = "AzureClientSecretCredential"
  12. )
  13. // Authorizer configs provide credentials from azidentity to connect to Azure services.
  14. type Authorizer interface {
  15. cloud.Authorizer
  16. GetCredential() (azcore.TokenCredential, error)
  17. }
  18. // SelectAuthorizerByType is an implementation of AuthorizerSelectorFn and acts as a register for Authorizer types
  19. func SelectAuthorizerByType(typeStr string) (Authorizer, error) {
  20. switch typeStr {
  21. case DefaultCredentialAuthorizerType:
  22. return &DefaultAzureCredentialHolder{}, nil
  23. case ClientSecretCredentialType:
  24. return &ClientSecretCredential{}, nil
  25. default:
  26. return nil, fmt.Errorf("azure: provider authorizer type '%s' is not valid", typeStr)
  27. }
  28. }
  29. type DefaultAzureCredentialHolder struct{}
  30. func (dac *DefaultAzureCredentialHolder) MarshalJSON() ([]byte, error) {
  31. fmap := make(map[string]any, 1)
  32. fmap[cloud.AuthorizerTypeProperty] = DefaultCredentialAuthorizerType
  33. return json.Marshal(fmap)
  34. }
  35. func (dac *DefaultAzureCredentialHolder) Validate() error {
  36. return nil
  37. }
  38. func (dac *DefaultAzureCredentialHolder) Equals(config cloud.Config) bool {
  39. if config == nil {
  40. return false
  41. }
  42. _, ok := config.(*DefaultAzureCredentialHolder)
  43. if !ok {
  44. return false
  45. }
  46. return true
  47. }
  48. func (dac *DefaultAzureCredentialHolder) Sanitize() cloud.Config {
  49. return &DefaultAzureCredentialHolder{}
  50. }
  51. func (dac *DefaultAzureCredentialHolder) GetCredential() (azcore.TokenCredential, error) {
  52. return azidentity.NewDefaultAzureCredential(nil)
  53. }
  54. type ClientSecretCredential struct {
  55. TenantID string `json:"tenantID"`
  56. ClientID string `json:"clientID"`
  57. ClientSecret string `json:"clientSecret"`
  58. }
  59. func (csc *ClientSecretCredential) Validate() error {
  60. if csc.TenantID == "" {
  61. return fmt.Errorf("ClientSecretCredential: missing Tenant ID")
  62. }
  63. if csc.ClientID == "" {
  64. return fmt.Errorf("ClientSecretCredential: missing Client ID")
  65. }
  66. if csc.ClientSecret == "" {
  67. return fmt.Errorf("ClientSecretCredential: missing Client Secret")
  68. }
  69. return nil
  70. }
  71. func (csc *ClientSecretCredential) Sanitize() cloud.Config {
  72. return &ClientSecretCredential{
  73. TenantID: csc.TenantID,
  74. ClientID: csc.ClientID,
  75. ClientSecret: cloud.Redacted,
  76. }
  77. }
  78. func (csc *ClientSecretCredential) Equals(config cloud.Config) bool {
  79. if config == nil {
  80. return false
  81. }
  82. thatConfig, ok := config.(*ClientSecretCredential)
  83. if !ok {
  84. return false
  85. }
  86. if csc.TenantID != thatConfig.TenantID {
  87. return false
  88. }
  89. if csc.ClientID != thatConfig.ClientID {
  90. return false
  91. }
  92. if csc.ClientSecret != thatConfig.ClientSecret {
  93. return false
  94. }
  95. return true
  96. }
  97. func (csc *ClientSecretCredential) MarshalJSON() ([]byte, error) {
  98. fmap := make(map[string]any, 1)
  99. fmap[cloud.AuthorizerTypeProperty] = ClientSecretCredentialType
  100. fmap["tenantID"] = csc.TenantID
  101. fmap["clientID"] = csc.ClientID
  102. fmap["clientSecret"] = csc.ClientSecret
  103. return json.Marshal(fmap)
  104. }
  105. func (csc *ClientSecretCredential) GetCredential() (azcore.TokenCredential, error) {
  106. cred, err := azidentity.NewClientSecretCredential(csc.TenantID, csc.ClientID, csc.ClientSecret, nil)
  107. if err != nil {
  108. return nil, fmt.Errorf("ClientSecretCredential: failed to retrieve credentials: %w", err)
  109. }
  110. return cred, nil
  111. }