Blob Storage
Example: azure-blob resource based on Azure Blob Storage
Configuration
This example configures an azure-blob and an azure-blob-account Resource Definition to enable workloads to use Azure Blob Storage.
The azure-blob-account
represent the Azure Storage Account and is shared across all workloads.
Workloads can use the azure-blob
resource type to request Azure Storage Containers with two different access policies:
basic-admin
(full access)basic-read-only
(read-only access)
From Score requesting a Azure Storage Container with full access looks like:
resources:
...
storage:
type: azure-blob
class: basic-admin
Infrastructure setup
The workload service account will automatically be assigned the necessary Azure Role.
graph TD;
subgraph Resource Group
subgraph account["Azure Storage Account"]
container["Azure Storage Container"]
end
k8s-service-account["K8s Service Account"] -- azure federated identity --> azure-managed-identity["Azure Managed Identity"]
azure-managed-identity -- owner role --> container
subgraph AKS Cluster
workload-pod["Workload Pod"] --> k8s-service-account
workload-pod -- operations --> container
end
end
Orchestrator setup
The Resource Graph is using delegator resources to expose shared resources with different access policies.
graph TD;
workload_1 --> k8s_sa_1["k8s_service_account_1, resource_type: k8s-service-account"]:::policy
az_fi_1 --> az_mi_1["azure_managed_identity, resource_type: azure-managed-identity"]:::policy
az_ra_1["azure_role_assignments, resource_type: azure-role-assignments"]:::policy --> az_mi_1
az_ra_1 --> az_rd_1["azure_role_definition, resource_type: azure-role-definition"]:::policy
az_fi_1["azure_federated_identity, resource_type: azure-federated-identity"]:::policy --> k8s_sa_1
workload_1 --> blob_1["delegator_blob_1, resource_type: azure-blob"]
az_rd_1 -- owner --> blob_1
workload_2 --> p_2["identities & roles setup similar to workload 1"]:::policy
workload_2 --> blob_2["delegator_blob_2, resource_type: azure-blob"]
p_2 -- reader --> blob_2
blob_1 --> shared.blob_1["shared.blob_1, resource_type: azure-blob"]
blob_2 --> shared.blob_1
shared.blob_1 --> blob_account["shared.main-blob-account, resource_type: azure-blob-account"]
classDef policy fill:#f96
Terraform docs
Requirements
Name | Version |
---|---|
terraform | >= 1.3.0 |
azuread | ~> 2.47 |
azurerm | ~> 3.91 |
humanitec | ~> 1.0 |
random | ~> 3.6 |
Providers
Name | Version |
---|---|
azuread | ~> 2.47 |
azurerm | ~> 3.91 |
humanitec | ~> 1.0 |
random | ~> 3.6 |
Modules
Name | Source | Version |
---|---|---|
azure_blob_account | ../../humanitec-resource-defs/azure-blob-account/basic | n/a |
blob_storage | ../../humanitec-resource-defs/azure-blob/basic | n/a |
blob_storage_admin | ../../humanitec-resource-defs/azure-blob/delegator | n/a |
blob_storage_reader | ../../humanitec-resource-defs/azure-blob/delegator | n/a |
federated_identity | ../../humanitec-resource-defs/azure-federated-identity/basic | n/a |
k8s_service_account | ../../humanitec-resource-defs/k8s/service-account | n/a |
managed_identity | ../../humanitec-resource-defs/azure-managed-identity/basic | n/a |
role_assignment | ../../humanitec-resource-defs/azure-role-assignments/basic | n/a |
role_definition_admin | ../../humanitec-resource-defs/azure-role-definition/echo | n/a |
role_definition_reader | ../../humanitec-resource-defs/azure-role-definition/echo | n/a |
workload | ../../humanitec-resource-defs/workload/service-account | n/a |
Resources
Inputs
Name | Description | Type | Default | Required |
---|---|---|---|---|
aks_cluster_issuer_url | AKS OIDC Issuer URL | string |
n/a | yes |
resource_group_name | Specifies the Name of the Resource Group within which created resources will reside. | string |
n/a | yes |
subscription_id | The Subscription ID which should be used. | string |
n/a | yes |
account_replication_type | Defines the type of replication to use for this storage account. | string |
"GRS" |
no |
account_tier | Defines the Tier to use for this storage account. | string |
"Standard" |
no |
container_access_type | The Access Level configured for this Container. | string |
"private" |
no |
name | Specifies the Name for created example application. | string |
"hum-rp-blob-storage-example" |
no |
prefix | Specifies the prefix used in default name for created resources. | string |
"hum-rp-blob-storage-ex-" |
no |
resource_packs_azure_rev | Azure Resource Pack git branch. | string |
"refs/heads/main" |
no |
resource_packs_azure_url | Azure Resource Pack git url. | string |
"https://github.com/humanitec-architecture/resource-packs-azure.git" |
no |
main.tf
(
view on GitHub
)
:
# Service principal used by Humanitec to provision resources
data "azurerm_resource_group" "main" {
name = var.resource_group_name
}
resource "azuread_application" "humanitec_provisioner" {
display_name = var.name
}
resource "azuread_service_principal" "humanitec_provisioner" {
client_id = azuread_application.humanitec_provisioner.client_id
}
resource "azuread_service_principal_password" "humanitec_provisioner" {
service_principal_id = azuread_service_principal.humanitec_provisioner.object_id
}
resource "azurerm_role_assignment" "resource_group" {
scope = data.azurerm_resource_group.main.id
role_definition_name = "Owner"
principal_id = azuread_service_principal.humanitec_provisioner.object_id
}
resource "humanitec_resource_account" "humanitec_provisioner" {
id = var.name
name = var.name
type = "azure"
credentials = jsonencode({
"appId" : azuread_service_principal.humanitec_provisioner.client_id,
"displayName" : azuread_application.humanitec_provisioner.display_name,
"password" : azuread_service_principal_password.humanitec_provisioner.value,
"tenant" : azuread_service_principal.humanitec_provisioner.application_tenant_id
})
depends_on = [
# Otherwise the account looses permissions before the resources are deleted
azurerm_role_assignment.resource_group
]
}
# Example application and resource definition criteria
resource "humanitec_application" "example" {
id = var.name
name = var.name
}
locals {
# Define the shared azure-blob-account resource id and class
azure_blob_account_res_id = "main-blob-account"
azure_blob_account_class = "default"
# Classes used to build the resource definition graph
blob_storage_basic_class = "basic"
blob_storage_admin_policy_class = "blob-storage-basic-admin"
blob_storage_reader_policy_class = "blob-storage-basic-reader"
# Classes that developers can select from
blob_storage_admin_class = "basic-admin"
blob_storage_reader_class = "basic-read-ony"
account_resource = "azure-blob-account.${local.azure_blob_account_class}#${local.azure_blob_account_res_id}"
blob_storage_scope = "/subscriptions/${var.subscription_id}/resourceGroups/${var.resource_group_name}/providers/Microsoft.Storage/storageAccounts/$${resources['${local.account_resource}'].outputs.name}/blobServices/default/containers/$${resources['azure-blob.${local.blob_storage_basic_class}'].outputs.container}"
# Azure build in role ids: https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles
build_in_azure_storage_blob_data_owner_role_id = "/providers/Microsoft.Authorization/roleDefinitions/b7e6dc6d-f1e8-4753-8033-0f276bb0955b"
build_in_azure_storage_blob_data_reader_role_id = "/providers/Microsoft.Authorization/roleDefinitions/2a2b9908-6ea1-4ae2-8e65-a410df84e7d1"
}
# Shared azure-blob-account resource
module "azure_blob_account" {
source = "github.com/humanitec-architecture/resource-packs-azure?ref=v2024-06-14//humanitec-resource-defs/azure-blob-account/basic"
resource_packs_azure_url = var.resource_packs_azure_url
resource_packs_azure_rev = var.resource_packs_azure_rev
append_logs_to_error = true
terraform_state = local.terraform_state
driver_account = humanitec_resource_account.humanitec_provisioner.id
subscription_id = var.subscription_id
resource_group_name = var.resource_group_name
prefix = var.prefix
account_tier = var.account_tier
account_replication_type = var.account_replication_type
}
resource "humanitec_resource_definition_criteria" "azure_blob_account" {
resource_definition_id = module.azure_blob_account.id
app_id = humanitec_application.example.id
res_id = local.azure_blob_account_res_id
class = local.azure_blob_account_class
force_delete = true
}
# Workload or shared blob-storage resources
module "blob_storage" {
source = "github.com/humanitec-architecture/resource-packs-azure?ref=v2024-06-14//humanitec-resource-defs/azure-blob/basic"
resource_packs_azure_url = var.resource_packs_azure_url
resource_packs_azure_rev = var.resource_packs_azure_rev
append_logs_to_error = true
terraform_state = local.terraform_state
driver_account = humanitec_resource_account.humanitec_provisioner.id
subscription_id = var.subscription_id
prefix = var.prefix
container_access_type = var.container_access_type
account_resource = local.account_resource
}
resource "humanitec_resource_definition_criteria" "blob_storage" {
resource_definition_id = module.blob_storage.id
app_id = humanitec_application.example.id
class = local.blob_storage_basic_class
force_delete = true
}
// Admin shared
// Exposed delegator resource definition
module "blob_storage_admin" {
source = "github.com/humanitec-architecture/resource-packs-azure?ref=v2024-06-14//humanitec-resource-defs/azure-blob/delegator"
prefix = "${var.prefix}admin-"
policy_resource_class = local.blob_storage_admin_policy_class
blob_storage_resource_class = local.blob_storage_basic_class
}
resource "humanitec_resource_definition_criteria" "blob_storage_admin" {
resource_definition_id = module.blob_storage_admin.id
app_id = humanitec_application.example.id
class = local.blob_storage_admin_class
force_delete = true
}
module "role_definition_admin" {
source = "github.com/humanitec-architecture/resource-packs-azure?ref=v2024-06-14//humanitec-resource-defs/azure-role-definition/echo"
prefix = "${var.prefix}admin-"
role_definition_id = local.build_in_azure_storage_blob_data_owner_role_id
role_definition_scope = local.blob_storage_scope
}
resource "humanitec_resource_definition_criteria" "role_definition_admin" {
resource_definition_id = module.role_definition_admin.id
app_id = humanitec_application.example.id
class = local.blob_storage_admin_policy_class
force_delete = true
}
// Reader shared
// Exposed delegator resource definition
module "blob_storage_reader" {
source = "github.com/humanitec-architecture/resource-packs-azure?ref=v2024-06-14//humanitec-resource-defs/azure-blob/delegator"
prefix = "${var.prefix}reader-"
policy_resource_class = local.blob_storage_reader_policy_class
blob_storage_resource_class = local.blob_storage_basic_class
}
resource "humanitec_resource_definition_criteria" "blob_storage_reader" {
resource_definition_id = module.blob_storage_reader.id
app_id = humanitec_application.example.id
class = local.blob_storage_reader_class
force_delete = true
}
module "role_definition_reader" {
source = "github.com/humanitec-architecture/resource-packs-azure?ref=v2024-06-14//humanitec-resource-defs/azure-role-definition/echo"
prefix = "${var.prefix}reader-"
role_definition_id = local.build_in_azure_storage_blob_data_reader_role_id
role_definition_scope = local.blob_storage_scope
}
resource "humanitec_resource_definition_criteria" "role_definition_reader" {
resource_definition_id = module.role_definition_reader.id
app_id = humanitec_application.example.id
class = local.blob_storage_reader_policy_class
force_delete = true
}
// Workload based
module "workload" {
source = "github.com/humanitec-architecture/resource-packs-azure?ref=v2024-06-14//humanitec-resource-defs/workload/service-account"
prefix = var.prefix
}
resource "humanitec_resource_definition_criteria" "workload" {
resource_definition_id = module.workload.id
app_id = humanitec_application.example.id
force_delete = true
}
module "k8s_service_account" {
source = "github.com/humanitec-architecture/resource-packs-azure?ref=v2024-06-14//humanitec-resource-defs/k8s/service-account"
prefix = var.prefix
}
resource "humanitec_resource_definition_criteria" "k8s_service_account" {
resource_definition_id = module.k8s_service_account.id
app_id = humanitec_application.example.id
force_delete = true
}
module "federated_identity" {
source = "github.com/humanitec-architecture/resource-packs-azure?ref=v2024-06-14//humanitec-resource-defs/azure-federated-identity/basic"
resource_packs_azure_url = var.resource_packs_azure_url
resource_packs_azure_rev = var.resource_packs_azure_rev
append_logs_to_error = true
terraform_state = local.terraform_state
driver_account = humanitec_resource_account.humanitec_provisioner.id
subscription_id = var.subscription_id
prefix = var.prefix
resource_group_name = var.resource_group_name
audience = ["api://AzureADTokenExchange"]
issuer = var.aks_cluster_issuer_url
parent_id = "$${resources.azure-managed-identity.outputs.id}"
subject = "system:serviceaccount:$${resources.k8s-namespace.outputs.namespace}:$${resources.k8s-service-account.outputs.name}"
}
resource "humanitec_resource_definition_criteria" "federated_identity" {
resource_definition_id = module.federated_identity.id
app_id = humanitec_application.example.id
force_delete = true
}
module "managed_identity" {
source = "github.com/humanitec-architecture/resource-packs-azure?ref=v2024-06-14//humanitec-resource-defs/azure-managed-identity/basic"
resource_packs_azure_url = var.resource_packs_azure_url
resource_packs_azure_rev = var.resource_packs_azure_rev
append_logs_to_error = true
terraform_state = local.terraform_state
driver_account = humanitec_resource_account.humanitec_provisioner.id
subscription_id = var.subscription_id
prefix = var.prefix
resource_group_name = var.resource_group_name
}
resource "humanitec_resource_definition_criteria" "managed_identity" {
resource_definition_id = module.managed_identity.id
app_id = humanitec_application.example.id
force_delete = true
}
module "role_assignment" {
source = "github.com/humanitec-architecture/resource-packs-azure?ref=v2024-06-14//humanitec-resource-defs/azure-role-assignments/basic"
resource_packs_azure_url = var.resource_packs_azure_url
resource_packs_azure_rev = var.resource_packs_azure_rev
append_logs_to_error = true
terraform_state = local.terraform_state
driver_account = humanitec_resource_account.humanitec_provisioner.id
subscription_id = var.subscription_id
prefix = var.prefix
role_definition_ids = "$${resources.workload>azure-role-definition.outputs.id}"
scopes = "$${resources.workload>azure-role-definition.outputs.scope}"
principal_id = "$${resources.azure-managed-identity.outputs.principal_id}"
}
resource "humanitec_resource_definition_criteria" "role_assignment" {
resource_definition_id = module.role_assignment.id
app_id = humanitec_application.example.id
force_delete = true
}
providers.tf
(
view on GitHub
)
:
terraform {
required_providers {
azuread = {
source = "hashicorp/azuread"
version = "~> 2.47"
}
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.91"
}
humanitec = {
source = "humanitec/humanitec"
version = "~> 1.0"
}
random = {
source = "hashicorp/random"
version = "~> 3.6"
}
}
required_version = ">= 1.3.0"
}
provider "humanitec" {
}
provider "azuread" {
}
provider "azurerm" {
features {}
subscription_id = var.subscription_id
}
state.tf
(
view on GitHub
)
:
# Resources required for the terraform backend
# More details https://developer.humanitec.com/integration-and-extensions/drivers/generic-drivers/terraform/
resource "random_string" "storage_account_suffix" {
length = 12
special = false
upper = false
}
resource "azurerm_storage_account" "tfstate" {
name = "humrp${random_string.storage_account_suffix.result}tfstate"
resource_group_name = data.azurerm_resource_group.main.name
location = data.azurerm_resource_group.main.location
account_tier = "Standard"
account_replication_type = "ZRS"
allow_nested_items_to_be_public = false
}
resource "azurerm_storage_container" "tfstate" {
name = var.name
storage_account_name = azurerm_storage_account.tfstate.name
container_access_type = "private"
}
locals {
terraform_state = {
subscription_id = var.subscription_id
resource_group_name = data.azurerm_resource_group.main.name
storage_account_name = azurerm_storage_account.tfstate.name
container_name = azurerm_storage_container.tfstate.name
# key_prefix is set by the respective resource definition
}
}
terraform.tfvars.example
(
view on GitHub
)
:
# Defines the type of replication to use for this storage account.
account_replication_type = "GRS"
# Defines the Tier to use for this storage account.
account_tier = "Standard"
# AKS OIDC Issuer URL
aks_cluster_issuer_url = ""
# The Access Level configured for this Container.
container_access_type = "private"
# Specifies the Name for created example application.
name = "hum-rp-blob-storage-example"
# Specifies the prefix used in default name for created resources.
prefix = "hum-rp-blob-storage-ex-"
# Specifies the Name of the Resource Group within which created resources will reside.
resource_group_name = ""
# Azure Resource Pack git branch.
resource_packs_azure_rev = "refs/tags/v2024-06-14"
# Azure Resource Pack git url.
resource_packs_azure_url = "https://github.com/humanitec-architecture/resource-packs-azure.git"
# The Subscription ID which should be used.
subscription_id = ""
variables.tf
(
view on GitHub
)
:
variable "resource_packs_azure_url" {
description = "Azure Resource Pack git url."
type = string
default = "https://github.com/humanitec-architecture/resource-packs-azure.git"
}
variable "resource_packs_azure_rev" {
description = "Azure Resource Pack git branch."
type = string
default = "refs/tags/v2024-06-14"
}
variable "subscription_id" {
description = "The Subscription ID which should be used."
type = string
}
variable "resource_group_name" {
description = "Specifies the Name of the Resource Group within which created resources will reside."
type = string
}
variable "name" {
description = "Specifies the Name for created example application."
type = string
default = "hum-rp-blob-storage-example"
}
variable "prefix" {
description = "Specifies the prefix used in default name for created resources."
type = string
default = "hum-rp-blob-storage-ex-"
}
variable "account_tier" {
description = "Defines the Tier to use for this storage account."
type = string
default = "Standard"
}
variable "account_replication_type" {
description = "Defines the type of replication to use for this storage account."
type = string
default = "GRS"
}
variable "container_access_type" {
description = "The Access Level configured for this Container."
type = string
default = "private"
}
variable "aks_cluster_issuer_url" {
description = "AKS OIDC Issuer URL"
type = string
}