{"record":{"id":"4f11f30ca212581b","repo":"apache/druid","slug":"either-set-key-or-sharedaccessstoragetoken-or","errorCode":null,"errorMessage":"Either set 'key' or 'sharedAccessStorageToken' or 'useAzureCredentialsChain' in the azure config. Please refer to azure documentation.","messagePattern":"Either set 'key' or 'sharedAccessStorageToken' or 'useAzureCredentialsChain' in the azure config\\. Please refer to azure documentation\\.","errorType":"validation","errorClass":"ISE","httpStatus":null,"severity":"critical","filePath":"extensions-core/azure-extensions/src/main/java/org/apache/druid/storage/azure/AzureStorageDruidModule.java","lineNumber":123,"sourceCode":"                       .build(AzureEntityFactory.class));\n    binder.install(new FactoryModuleBuilder()\n                       .build(AzureCloudBlobIteratorFactory.class));\n    binder.install(new FactoryModuleBuilder()\n                       .build(AzureCloudBlobIterableFactory.class));\n  }\n\n\n  @Provides\n  @LazySingleton\n  public AzureClientFactory getAzureClientFactory(final AzureAccountConfig config)\n  {\n    if (StringUtils.isEmpty(config.getAccount())) {\n      throw new ISE(\"Set 'account' to the storage account that needs to be configured in the azure config.\"\n          + \" Please refer to azure documentation.\");\n    }\n\n    if (StringUtils.isEmpty(config.getKey()) && StringUtils.isEmpty(config.getSharedAccessStorageToken()) && BooleanUtils.isNotTrue(config.getUseAzureCredentialsChain())) {\n      throw new ISE(\"Either set 'key' or 'sharedAccessStorageToken' or 'useAzureCredentialsChain' in the azure config.\"\n          + \" Please refer to azure documentation.\");\n    }\n\n    /* Azure named keys and sas tokens are mutually exclusive with each other and with azure keychain auth,\n    but any form of auth supported by the DefaultAzureCredentialChain is not mutually exclusive, e.g. you can have\n    environment credentials or workload credentials or managed credentials using the same chain.\n    **/\n    if (!StringUtils.isEmpty(config.getKey()) && !StringUtils.isEmpty(config.getSharedAccessStorageToken()) ||\n        !StringUtils.isEmpty(config.getKey()) && BooleanUtils.isTrue(config.getUseAzureCredentialsChain()) ||\n        !StringUtils.isEmpty(config.getSharedAccessStorageToken()) && BooleanUtils.isTrue(config.getUseAzureCredentialsChain())\n    ) {\n      throw new ISE(\"Set only one of 'key' or 'sharedAccessStorageToken' or 'useAzureCredentialsChain' in the azure config.\"\n          + \" Please refer to azure documentation.\");\n    }\n    return new AzureClientFactory(config);\n  }\n\n  @Provides","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-core/azure-extensions/src/main/java/org/apache/druid/storage/azure/AzureStorageDruidModule.java#L105-L141","documentation":"AzureAccountConfig requires credentials: either a shared key, a SAS token, or opting into the DefaultAzureCredentialChain. If all three (druid.azure.key, druid.azure.sharedAccessStorageToken, druid.azure.useAzureCredentialsChain) are unset/empty, getAzureClientFactory throws this ISE at startup.","triggerScenarios":"Provisioning the AzureClientFactory when key, sharedAccessStorageToken are empty AND useAzureCredentialsChain is not true — i.e. no authentication method configured.","commonSituations":"Setting only druid.azure.account and forgetting credentials; removing a key for security migration but not enabling the credentials chain; running in an environment without Azure managed identity while expecting chain auth.","solutions":["Set druid.azure.key to the storage account key (simplest fix)","Or set druid.azure.sharedAccessStorageToken to a valid SAS token","Or set druid.azure.useAzureCredentialsChain=true and ensure a DefaultAzureCredentialChain source (env vars, managed identity, az CLI) is available","Verify the combination is mutually exclusive as documented — don't set key and SAS token together"],"exampleFix":"// before\ndruid.azure.account=mystorageaccount\n// after\ndruid.azure.account=mystorageaccount\ndruid.azure.key=<account-key>\n# or: druid.azure.useAzureCredentialsChain=true","handlingStrategy":"validation","validationCode":"boolean hasAuth = notEmpty(props.get(\"druid.azure.key\"))\n    || notEmpty(props.get(\"druid.azure.sharedAccessStorageToken\"))\n    || Boolean.parseBoolean(props.getOrDefault(\"druid.azure.useAzureCredentialsChain\", \"false\"));\nif (!hasAuth) throw new IllegalStateException(\"Configure azure key, SAS token, or credentials chain\");","typeGuard":null,"tryCatchPattern":"try { injector.getInstance(AzureClientFactory.class); } catch (ProvisionException e) { log.error(\"Azure auth config missing: %s\", e.getMessage()); }","preventionTips":["Validate exactly one auth method (key XOR SAS XOR credentials chain) at deploy time","When migrating off stored keys, enable useAzureCredentialsChain before removing druid.azure.key","Ensure managed identity/az CLI is actually available where chain auth is used","Never commit keys; use secret management feeding runtime.properties"],"tags":["azure","config","authentication","startup"],"backgroundTag":"missing-credentials","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}