diff --git a/docs/features/techdocs/configuration.md b/docs/features/techdocs/configuration.md index efed37fc69..f588be7c8c 100644 --- a/docs/features/techdocs/configuration.md +++ b/docs/features/techdocs/configuration.md @@ -91,12 +91,14 @@ techdocs: # (Required) Azure Blob Storage Container Name containerName: 'techdocs-storage' - # (Optional) An API key is required to write to a storage container. - # If not set, environment variables will be used to authenticate. - #https://docs.microsoft.com/en-us/azure/storage/common/storage-auth?toc=/azure/storage/blobs/toc.json + # (Required) An account name is required to write to a storage blob container. + # https://docs.microsoft.com/pt-br/rest/api/storageservices/authorize-with-shared-key credentials: - account: - $env: TECHDOCS_AZURE_BLOB_STORAGE_ACCOUNT + accountName: + $env: TECHDOCS_AZURE_BLOB_STORAGE_ACCOUNT_NAME + # (Optional) An account key is required to write to a storage container. + # If missing,AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET environment variable will be used. + # https://docs.microsoft.com/en-us/azure/storage/common/storage-auth?toc=/azure/storage/blobs/toc.json accountKey: $env: TECHDOCS_AZURE_BLOB_STORAGE_ACCOUNT_KEY ``` diff --git a/docs/features/techdocs/using-cloud-storage.md b/docs/features/techdocs/using-cloud-storage.md index 402ae657ea..f384270379 100644 --- a/docs/features/techdocs/using-cloud-storage.md +++ b/docs/features/techdocs/using-cloud-storage.md @@ -212,33 +212,17 @@ techdocs: type: 'azureBlobStorage' ``` -**2. Service account credentials** +**2. Create an Azure Blob Storage Container** -To get credentials, access the Azure Portal and go to "Settings > Access Keys", -and get your Storage account name and Primary Key. +Create a dedicated container for TechDocs sites. +[Refer to the official documentation](https://docs.microsoft.com/pt-br/azure/storage/blobs/storage-quickstart-blobs-portal). -```yaml -techdocs: - publisher: - type: 'azureBlobStorage' - azureBlobStorage: - credentials: - account: - $env: TECHDOCS_AZURE_BLOB_STORAGE_ACCOUNT - accountKey: - $env: TECHDOCS_AZURE_BLOB_STORAGE_ACCOUNT_KEY -``` +TechDocs will publish documentation to this container and will fetch files from +here to serve documentation in Backstage. Note that the container names are +globally unique. -**3. Azure Blob Storage Container** - -Create a dedicated container for TechDocs sites. techdocs-backend will publish -documentation to this container. TechDocs will fetch files from here to serve -documentation in Backstage. - -To create a new container, access "Blob Service > Containers > New Container". - -Set the name of the container to -`techdocs.publisher.azureBlobStorage.containerName`. +Set the config `techdocs.publisher.azureBlobStorage.containerName` in your +`app-config.yaml` to the name of the container you just created. ```yaml techdocs: @@ -246,9 +230,49 @@ techdocs: type: 'azureBlobStorage' azureBlobStorage: containerName: 'name-of-techdocs-storage-container' +``` + +**3a. (Recommended) Authentication using environment variable** + +Set the config `techdocs.publisher.azureBlobStorage.credentials.accountName` in +your `app-config.yaml` to the your account name. + +The storage blob client will automatically use the environment variable +`AZURE_TENANT_ID`, `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET` to authenticate with +Azure Blob Storage. +https://docs.microsoft.com/pt-br/azure/storage/common/storage-auth-aad for more +details. + +```yaml +techdocs: + publisher: + type: 'azureBlobStorage' + azureBlobStorage: + containerName: 'name-of-techdocs-storage-bucket' credentials: - account: - $env: TECHDOCS_AZURE_BLOB_STORAGE_ACCOUNT + accountName: + $env: TECHDOCS_AZURE_BLOB_STORAGE_ACCOUNT_NAME +``` + +**3b. Authentication using app-config.yaml** + +If you do not prefer (3a) and optionally like to use a service account, you can +follow these steps. + +To get credentials, access the Azure Portal and go to "Settings > Access Keys", +and get your Storage account name and Primary Key. +https://docs.microsoft.com/pt-br/rest/api/storageservices/authorize-with-shared-key +for more details. + +```yaml +techdocs: + publisher: + type: 'azureBlobStorage' + azureBlobStorage: + containerName: 'name-of-techdocs-storage-bucket' + credentials: + accountName: + $env: TECHDOCS_AZURE_BLOB_STORAGE_ACCOUNT_NAME accountKey: $env: TECHDOCS_AZURE_BLOB_STORAGE_ACCOUNT_KEY ``` diff --git a/packages/techdocs-common/package.json b/packages/techdocs-common/package.json index 1834248c3a..2a065600a1 100644 --- a/packages/techdocs-common/package.json +++ b/packages/techdocs-common/package.json @@ -37,6 +37,7 @@ }, "dependencies": { "@aws-sdk/client-s3": "^3.1.0", + "@azure/identity": "^1.2.2", "@azure/storage-blob": "^12.4.0", "@backstage/backend-common": "^0.5.1", "@backstage/catalog-model": "^0.7.0", diff --git a/packages/techdocs-common/src/stages/publish/azureBlobStorage.test.ts b/packages/techdocs-common/src/stages/publish/azureBlobStorage.test.ts index 95e4a52f62..9d2ee1ba9b 100644 --- a/packages/techdocs-common/src/stages/publish/azureBlobStorage.test.ts +++ b/packages/techdocs-common/src/stages/publish/azureBlobStorage.test.ts @@ -57,7 +57,7 @@ beforeEach(async () => { type: 'azureBlobStorage', azureBlobStorage: { credentials: { - account: 'account', + accountName: 'accountName', accountKey: 'accountKey', }, containerName: 'containerName', diff --git a/packages/techdocs-common/src/stages/publish/azureBlobStorage.ts b/packages/techdocs-common/src/stages/publish/azureBlobStorage.ts index 7ba4d35892..abfa9d71bf 100644 --- a/packages/techdocs-common/src/stages/publish/azureBlobStorage.ts +++ b/packages/techdocs-common/src/stages/publish/azureBlobStorage.ts @@ -20,6 +20,7 @@ import { BlobUploadCommonResponse, StorageSharedKeyCredential, } from '@azure/storage-blob'; +import { DefaultAzureCredential } from '@azure/identity'; import { Logger } from 'winston'; import { Entity, EntityName } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; @@ -43,29 +44,39 @@ export class AzureBlobStoragePublish implements PublisherBase { ); } catch (error) { throw new Error( - "Since techdocs.publisher.type is set to 'awsS3' in your app config, " + - 'techdocs.publisher.awsS3.bucketName is required.', + "Since techdocs.publisher.type is set to 'azureBlobStorage' in your app config, " + + 'techdocs.publisher.azureBlobStorage.containerName is required.', ); } - // Credentials is an optional config. If missing, default AWS environment variables - // or AWS shared credentials file at ~/.aws/credentials will be used to authenticate - // https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/loading-node-credentials-environment.html - // https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/loading-node-credentials-shared.html - let account = ''; - let accountKey = ''; - account = - config.getOptionalString( - 'techdocs.publisher.azureBlobStorage.credentials.account', - ) || ''; - accountKey = - config.getOptionalString( - 'techdocs.publisher.azureBlobStorage.credentials.accountKey', - ) || ''; + let accountName = ''; + try { + accountName = config.getString( + 'techdocs.publisher.azureBlobStorage.credentials.accountName', + ); + } catch (error) { + throw new Error( + "Since techdocs.publisher.type is set to 'azureBlobStorage' in your app config, " + + 'techdocs.publisher.azureBlobStorage.credentials.accountName is required.', + ); + } + + // Credentials is an optional config. If missing, default Azure Blob Storage environment variables + // https://docs.microsoft.com/pt-br/azure/storage/common/storage-auth-aad-app + const accountKey = config.getOptionalString( + 'techdocs.publisher.azureBlobStorage.credentials.accountKey', + ); + + let credential; + if (accountKey) { + console.log('accountKey =>', accountKey); + credential = new StorageSharedKeyCredential(accountName, accountKey); + } else { + credential = new DefaultAzureCredential(); + } - const credential = new StorageSharedKeyCredential(account, accountKey); const storageClient = new BlobServiceClient( - `https://${account}.blob.core.windows.net`, + `https://${accountName}.blob.core.windows.net`, credential, ); @@ -129,7 +140,6 @@ export class AzureBlobStoragePublish implements PublisherBase { `${entityRootDir}/${relativeFilePath}`, ); // Azure Blob Storage Container file relative path - // TODO: Upload in chunks of ~10 files instead of all files at once. return limiter(async () => { await uploadPromises.push( this.storageClient diff --git a/packages/techdocs-common/src/stages/publish/publish.test.ts b/packages/techdocs-common/src/stages/publish/publish.test.ts index a563e53a9b..4ae59a597e 100644 --- a/packages/techdocs-common/src/stages/publish/publish.test.ts +++ b/packages/techdocs-common/src/stages/publish/publish.test.ts @@ -115,7 +115,7 @@ describe('Publisher', () => { type: 'azureBlobStorage', azureBlobStorage: { credentials: { - account: 'account', + accountName: 'accountName', accountKey: 'accountKey', }, containerName: 'containerName', diff --git a/plugins/techdocs/config.d.ts b/plugins/techdocs/config.d.ts index f7903ea3fb..0af3ab4290 100644 --- a/plugins/techdocs/config.d.ts +++ b/plugins/techdocs/config.d.ts @@ -128,24 +128,24 @@ export interface Config { */ azureBlobStorage?: { /** - * (Optional) Credentials used to access a storage container. - * If not set, environment variables will be used to authenticate. - * https://docs.microsoft.com/en-us/azure/storage/common/storage-auth?toc=/azure/storage/blobs/toc.json + * (Required) Credentials used to access a storage container. * @visibility secret */ - credentials?: { + credentials: { /** * Account access name * attr: 'account' - accepts a string value * @visibility secret */ - account: string; + accountName: string; /** - * Account secret primary key + * (Optional) Account secret primary key + * If not set, environment variables will be used to authenticate. + * https://docs.microsoft.com/en-us/azure/storage/common/storage-auth?toc=/azure/storage/blobs/toc.json * attr: 'accountKey' - accepts a string value * @visibility secret */ - accountKey: string; + accountKey?: string; }; /** * (Required) Cloud Storage Container Name