Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/reference/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,11 @@ The following settings are available:
`azure.storage.accountName`
: The blob storage account name. Defaults to environment variable `AZURE_STORAGE_ACCOUNT_NAME`.

`azure.storage.endpoint`
: :::{versionadded} 25.11.0-edge
:::
: The blob storage service endpoint e.g. `https://nfbatch1.blob.core.windows.net`.
Copy link
Collaborator

@christopher-hakkaart christopher-hakkaart Nov 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
: The blob storage service endpoint e.g. `https://nfbatch1.blob.core.windows.net`.
: The blob storage service endpoint. For example, `https://nfbatch1.blob.core.windows.net`.


`azure.storage.fileShares.<name>.mountOptions`
: The file share mount options.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,17 +169,11 @@ class AzHelper {
return client.generateAccountSas(signature)
}

static String generateAccountSas(String accountName, String accountKey, Duration duration) {
final client = getOrCreateBlobServiceWithKey(accountName, accountKey)
return generateAccountSas(client, duration)
}

@Memoized
static synchronized BlobServiceClient getOrCreateBlobServiceWithKey(String accountName, String accountKey) {
static synchronized BlobServiceClient getOrCreateBlobServiceWithKey(String accountName, String accountKey, String endpoint) {
log.debug "Creating Azure blob storage client -- accountName=$accountName; accountKey=${accountKey?.substring(0,5)}.."

final credential = new StorageSharedKeyCredential(accountName, accountKey)
final endpoint = String.format(Locale.ROOT, "https://%s.blob.core.windows.net", accountName)

return new BlobServiceClientBuilder()
.endpoint(endpoint)
Expand All @@ -189,16 +183,14 @@ class AzHelper {
}

@Memoized
static synchronized BlobServiceClient getOrCreateBlobServiceWithToken(String accountName, String sasToken) {
static synchronized BlobServiceClient getOrCreateBlobServiceWithToken(String accountName, String sasToken, String endpoint) {
if( !sasToken )
throw new IllegalArgumentException("Missing Azure blob SAS token")
if( sasToken.length()<100 )
throw new IllegalArgumentException("Invalid Azure blob SAS token -- offending value: $sasToken")

log.debug "Creating Azure blob storage client -- accountName: $accountName; sasToken: ${sasToken?.substring(0,10)}.."

final endpoint = String.format(Locale.ROOT, "https://%s.blob.core.windows.net", accountName)

return new BlobServiceClientBuilder()
.endpoint(endpoint)
.sasToken(sasToken)
Expand All @@ -207,11 +199,9 @@ class AzHelper {
}

@Memoized
static synchronized BlobServiceClient getOrCreateBlobServiceWithServicePrincipal(String accountName, String clientId, String clientSecret, String tenantId) {
static synchronized BlobServiceClient getOrCreateBlobServiceWithServicePrincipal(String accountName, String clientId, String clientSecret, String tenantId, String endpoint) {
log.debug "Creating Azure Blob storage client using Service Principal credentials"

final endpoint = String.format(Locale.ROOT, "https://%s.blob.core.windows.net", accountName)

final credential = new ClientSecretCredentialBuilder()
.clientId(clientId)
.clientSecret(clientSecret)
Expand All @@ -226,11 +216,9 @@ class AzHelper {
}

@Memoized
static synchronized BlobServiceClient getOrCreateBlobServiceWithManagedIdentity(String accountName, String clientId) {
static synchronized BlobServiceClient getOrCreateBlobServiceWithManagedIdentity(String accountName, String clientId, String endpoint) {
log.debug "Creating Azure blob storage client using Managed Identity ${clientId ?: '<system-assigned identity>'}"

final endpoint = String.format(Locale.ROOT, "https://%s.blob.core.windows.net", accountName)

final credentialBuilder = new ManagedIdentityCredentialBuilder()
if( clientId )
credentialBuilder.clientId(clientId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ class AzStorageOpts implements ConfigScope {
""")
final String accountName

@ConfigOption
@Description("""
The blob storage service endpoint e.g. `https://nfbatch1.blob.core.windows.net`.
""")
final String endpoint

@ConfigOption
@Description("""
The blob storage shared access signature (SAS) token, which can be provided instead of an account key. Defaults to environment variable `AZURE_STORAGE_SAS_TOKEN`.
Expand All @@ -65,6 +71,7 @@ class AzStorageOpts implements ConfigScope {
assert config!=null
this.accountKey = config.accountKey ?: env.get('AZURE_STORAGE_ACCOUNT_KEY')
this.accountName = config.accountName ?: env.get('AZURE_STORAGE_ACCOUNT_NAME')
this.endpoint = parseEndpoint(config.endpoint as String, accountName)
this.sasToken = config.sasToken ?: env.get('AZURE_STORAGE_SAS_TOKEN')
this.tokenDuration = (config.tokenDuration as Duration) ?: Duration.of('48h')
this.fileShares = parseFileShares(config.fileShares instanceof Map ? config.fileShares as Map<String, Map>
Expand All @@ -76,10 +83,19 @@ class AzStorageOpts implements ConfigScope {
Map<String, Object> props = new HashMap<>();
props.put(AzFileSystemProvider.AZURE_STORAGE_ACCOUNT_KEY, accountKey)
props.put(AzFileSystemProvider.AZURE_STORAGE_ACCOUNT_NAME, accountName)
props.put(AzFileSystemProvider.AZURE_STORAGE_ENDPOINT, endpoint)
props.put(AzFileSystemProvider.AZURE_STORAGE_SAS_TOKEN, sasToken)
return props
}

static String parseEndpoint(String endpoint, String accountName) {
if( endpoint )
return endpoint
if( accountName )
return String.format(Locale.ROOT, "https://%s.blob.core.windows.net", accountName)
return null
}

static Map<String,AzFileShareOpts> parseFileShares(Map<String,Map> shares) {
final result = new LinkedHashMap<String,AzFileShareOpts>()
shares.each { Map.Entry<String, Map> entry ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class AzFileSystemProvider extends FileSystemProvider {

public static final String AZURE_STORAGE_ACCOUNT_NAME = 'AZURE_STORAGE_ACCOUNT_NAME'
public static final String AZURE_STORAGE_ACCOUNT_KEY = 'AZURE_STORAGE_ACCOUNT_KEY'
public static final String AZURE_STORAGE_ENDPOINT = 'AZURE_STORAGE_ENDPOINT'
public static final String AZURE_STORAGE_SAS_TOKEN = 'AZURE_STORAGE_SAS_TOKEN'

public static final String AZURE_CLIENT_ID = 'AZURE_CLIENT_ID'
Expand Down Expand Up @@ -110,20 +111,20 @@ class AzFileSystemProvider extends FileSystemProvider {
return uri.authority.toLowerCase()
}

protected BlobServiceClient createBlobServiceWithKey(String accountName, String accountKey) {
AzHelper.getOrCreateBlobServiceWithKey(accountName, accountKey)
protected BlobServiceClient createBlobServiceWithKey(String accountName, String accountKey, String endpoint) {
AzHelper.getOrCreateBlobServiceWithKey(accountName, accountKey, endpoint)
}

protected BlobServiceClient createBlobServiceWithToken(String accountName, String sasToken) {
AzHelper.getOrCreateBlobServiceWithToken(accountName, sasToken)
protected BlobServiceClient createBlobServiceWithToken(String accountName, String sasToken, String endpoint) {
AzHelper.getOrCreateBlobServiceWithToken(accountName, sasToken, endpoint)
}

protected BlobServiceClient createBlobServiceWithServicePrincipal(String accountName, String clientId, String clientSecret, String tenantId) {
AzHelper.getOrCreateBlobServiceWithServicePrincipal(accountName, clientId, clientSecret, tenantId)
protected BlobServiceClient createBlobServiceWithServicePrincipal(String accountName, String clientId, String clientSecret, String tenantId, String endpoint) {
AzHelper.getOrCreateBlobServiceWithServicePrincipal(accountName, clientId, clientSecret, tenantId, endpoint)
}

protected BlobServiceClient createBlobServiceWithManagedIdentity(String accountName, String clientId) {
AzHelper.getOrCreateBlobServiceWithManagedIdentity(accountName, clientId)
protected BlobServiceClient createBlobServiceWithManagedIdentity(String accountName, String clientId, String endpoint) {
AzHelper.getOrCreateBlobServiceWithManagedIdentity(accountName, clientId, endpoint)
}

/**
Expand Down Expand Up @@ -190,6 +191,7 @@ class AzFileSystemProvider extends FileSystemProvider {

final accountName = config.get(AZURE_STORAGE_ACCOUNT_NAME) as String
final accountKey = config.get(AZURE_STORAGE_ACCOUNT_KEY) as String
final endpoint = config.get(AZURE_STORAGE_ENDPOINT) as String
final sasToken = config.get(AZURE_STORAGE_SAS_TOKEN) as String

final servicePrincipalId = config.get(AZURE_CLIENT_ID) as String
Expand All @@ -205,17 +207,17 @@ class AzFileSystemProvider extends FileSystemProvider {
BlobServiceClient client

if( managedIdentityUser || managedIdentitySystem ) {
client = createBlobServiceWithManagedIdentity(accountName, managedIdentityUser)
client = createBlobServiceWithManagedIdentity(accountName, managedIdentityUser, endpoint)
}
else if( servicePrincipalSecret && servicePrincipalId && tenantId ) {
client = createBlobServiceWithServicePrincipal(accountName, servicePrincipalId, servicePrincipalSecret, tenantId)
client = createBlobServiceWithServicePrincipal(accountName, servicePrincipalId, servicePrincipalSecret, tenantId, endpoint)
}
else if( sasToken ) {
client = createBlobServiceWithToken(accountName, sasToken)
client = createBlobServiceWithToken(accountName, sasToken, endpoint)
this.sasToken = sasToken
}
else if( accountKey ) {
client = createBlobServiceWithKey(accountName, accountKey)
client = createBlobServiceWithKey(accountName, accountKey, endpoint)
this.accountKey = accountKey
}
else {
Expand Down
Loading