How to use Azure Managed Identity for authentication and authorization for Ruby On Rails Active Storage?
Opened this issue · 0 comments
avivansh commented
Current setup
azure:
service: AzureStorage
storage_account_name: <%= VaultService.get_secret("AZURE-STORAGE::AZURE-STORAGE-ACCOUNT-NAME") %>
storage_access_key: <%= VaultService.get_secret("AZURE-STORAGE::AZURE-STORAGE-ACCOUNT-ACCESS-KEY") %>
container: <%= VaultService.get_secret('AZURE-ATTACHMENTS-BUCKET-NAME') %>
Given the implementation of accessing Azure Storage using Access Token. Link
require "azure/storage/common"
access_token = <your initial access token>
# Creating an instance of `Azure::Storage::Common::Core::TokenCredential`
token_credential = Azure::Storage::Common::Core::TokenCredential.new access_token
token_signer = Azure::Storage::Common::Core::Auth::TokenSigner.new token_credential
blob_token_client = Azure::Storage::Blob::BlobService.new(storage_account_name: <your_account_name>, signer: token_signer)
Given the implementation of Active Storage for Ruby on Rails. It uses azure-storage-blob gem under the hood.
link
def initialize(storage_account_name:, storage_access_key:, container:, public: false, **options)
@client = Azure::Storage::Blob::BlobService.create(storage_account_name: storage_account_name, storage_access_key: storage_access_key, **options)
@signer = Azure::Storage::Common::Core::Auth::SharedAccessSignature.new(storage_account_name, storage_access_key)
@container = container
@public = public
end
New Setup, config/storage.yml
azure:
service: AzureStorage
storage_account_name: <%= VaultService.get_secret("AZURE-STORAGE::AZURE-STORAGE-ACCOUNT-NAME") %>
container: <%= VaultService.get_secret('AZURE-ATTACHMENTS-BUCKET-NAME') %>
Monkey patched to use the above information to use active storage using managed identity
module ActiveStorage
class Service::AzureStorageService < Service
def initialize(storage_account_name:, container:, public: false, **options)
access_token = AzureAd::ManagedIdentityTokenProvider.new('https://storage.azure.com/', client_id: ENV['AKS_MANAGED_IDENTITY_ID']).get_authentication_header.split(' ').last
# Creating an instance of `Azure::Storage::Common::Core::TokenCredential`
token_credential = ::Azure::Storage::Common::Core::TokenCredential.new access_token
token_signer = ::Azure::Storage::Common::Core::Auth::TokenSigner.new token_credential
@client = Azure::Storage::Blob::BlobService.create(storage_account_name: storage_account_name, signer: token_signer, **options)
user_delegation_key = @client.get_user_delegation_key(DateTime.now - 1.minute, DateTime.now + 6.day + 23.hours)
@signer = Azure::Storage::Common::Core::Auth::SharedAccessSignature.new(storage_account_name: storage_account_name, user_delegation_key: user_delegation_key )
@container = container
@public = public
rescue StandardError => e
raise e unless Rake.respond_to?(:application) && (!Rake.application.top_level_tasks.exclude?('assets:precompile') || !Rake.application.top_level_tasks.exclude?('source_map:upload_source_map'))
end
end
end
Is this approach correct? (I am yet to test this.). Also, is there any other approach on how to achieve this? I have posted the question on stackoverflow as well.