credentials.ts 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. import { config } from '@grafana/runtime';
  2. import {
  3. AzureAuthType,
  4. AzureCloud,
  5. AzureCredentials,
  6. AzureDataSourceInstanceSettings,
  7. AzureDataSourceSettings,
  8. ConcealedSecret,
  9. } from './types';
  10. const concealed: ConcealedSecret = Symbol('Concealed client secret');
  11. export function getAuthType(options: AzureDataSourceSettings | AzureDataSourceInstanceSettings): AzureAuthType {
  12. if (!options.jsonData.azureAuthType) {
  13. // If authentication type isn't explicitly specified and datasource has client credentials,
  14. // then this is existing datasource which is configured for app registration (client secret)
  15. if (options.jsonData.tenantId && options.jsonData.clientId) {
  16. return 'clientsecret';
  17. }
  18. // For newly created datasource with no configuration, managed identity is the default authentication type
  19. // if they are enabled in Grafana config
  20. return config.azure.managedIdentityEnabled ? 'msi' : 'clientsecret';
  21. }
  22. return options.jsonData.azureAuthType;
  23. }
  24. function getDefaultAzureCloud(): string {
  25. switch (config.azure.cloud) {
  26. case AzureCloud.Public:
  27. case AzureCloud.None:
  28. case undefined:
  29. return 'azuremonitor';
  30. case AzureCloud.China:
  31. return 'chinaazuremonitor';
  32. case AzureCloud.USGovernment:
  33. return 'govazuremonitor';
  34. case AzureCloud.Germany:
  35. return 'germanyazuremonitor';
  36. default:
  37. throw new Error(`The cloud '${config.azure.cloud}' not supported.`);
  38. }
  39. }
  40. export function getAzurePortalUrl(azureCloud: string): string {
  41. switch (azureCloud) {
  42. case 'azuremonitor':
  43. return 'https://portal.azure.com';
  44. case 'chinaazuremonitor':
  45. return 'https://portal.azure.cn';
  46. case 'govazuremonitor':
  47. return 'https://portal.azure.us';
  48. case 'germanyazuremonitor':
  49. return 'https://portal.microsoftazure.de';
  50. default:
  51. throw new Error('The cloud not supported.');
  52. }
  53. }
  54. export function getAzureCloud(options: AzureDataSourceSettings | AzureDataSourceInstanceSettings): string {
  55. const authType = getAuthType(options);
  56. switch (authType) {
  57. case 'msi':
  58. // In case of managed identity, the cloud is always same as where Grafana is hosted
  59. return getDefaultAzureCloud();
  60. case 'clientsecret':
  61. return options.jsonData.cloudName || getDefaultAzureCloud();
  62. }
  63. }
  64. function getSecret(options: AzureDataSourceSettings): undefined | string | ConcealedSecret {
  65. if (options.secureJsonFields.clientSecret) {
  66. // The secret is concealed on server
  67. return concealed;
  68. } else {
  69. const secret = options.secureJsonData?.clientSecret;
  70. return typeof secret === 'string' && secret.length > 0 ? secret : undefined;
  71. }
  72. }
  73. export function isCredentialsComplete(credentials: AzureCredentials): boolean {
  74. switch (credentials.authType) {
  75. case 'msi':
  76. return true;
  77. case 'clientsecret':
  78. return !!(credentials.azureCloud && credentials.tenantId && credentials.clientId && credentials.clientSecret);
  79. }
  80. }
  81. export function getCredentials(options: AzureDataSourceSettings): AzureCredentials {
  82. const authType = getAuthType(options);
  83. switch (authType) {
  84. case 'msi':
  85. if (config.azure.managedIdentityEnabled) {
  86. return {
  87. authType: 'msi',
  88. defaultSubscriptionId: options.jsonData.subscriptionId,
  89. };
  90. } else {
  91. // If authentication type is managed identity but managed identities were disabled in Grafana config,
  92. // then we should fallback to an empty app registration (client secret) configuration
  93. return {
  94. authType: 'clientsecret',
  95. azureCloud: getDefaultAzureCloud(),
  96. };
  97. }
  98. case 'clientsecret':
  99. return {
  100. authType: 'clientsecret',
  101. azureCloud: options.jsonData.cloudName || getDefaultAzureCloud(),
  102. tenantId: options.jsonData.tenantId,
  103. clientId: options.jsonData.clientId,
  104. clientSecret: getSecret(options),
  105. defaultSubscriptionId: options.jsonData.subscriptionId,
  106. };
  107. }
  108. }
  109. export function updateCredentials(
  110. options: AzureDataSourceSettings,
  111. credentials: AzureCredentials
  112. ): AzureDataSourceSettings {
  113. switch (credentials.authType) {
  114. case 'msi':
  115. if (!config.azure.managedIdentityEnabled) {
  116. throw new Error('Managed Identity authentication is not enabled in Grafana config.');
  117. }
  118. options = {
  119. ...options,
  120. jsonData: {
  121. ...options.jsonData,
  122. azureAuthType: 'msi',
  123. subscriptionId: credentials.defaultSubscriptionId,
  124. },
  125. };
  126. return options;
  127. case 'clientsecret':
  128. options = {
  129. ...options,
  130. jsonData: {
  131. ...options.jsonData,
  132. azureAuthType: 'clientsecret',
  133. cloudName: credentials.azureCloud || getDefaultAzureCloud(),
  134. tenantId: credentials.tenantId,
  135. clientId: credentials.clientId,
  136. subscriptionId: credentials.defaultSubscriptionId,
  137. },
  138. secureJsonData: {
  139. ...options.secureJsonData,
  140. clientSecret:
  141. typeof credentials.clientSecret === 'string' && credentials.clientSecret.length > 0
  142. ? credentials.clientSecret
  143. : undefined,
  144. },
  145. secureJsonFields: {
  146. ...options.secureJsonFields,
  147. clientSecret: typeof credentials.clientSecret === 'symbol',
  148. },
  149. };
  150. return options;
  151. }
  152. }