Skip to content

feat(infra): provision Azure Blob Storage for cath-service - #748

Merged
junaidiqbalmoj merged 5 commits into
masterfrom
feature/569-azure-blob-storage
Jun 19, 2026
Merged

feat(infra): provision Azure Blob Storage for cath-service#748
junaidiqbalmoj merged 5 commits into
masterfrom
feature/569-azure-blob-storage

Conversation

@junaidiqbalmoj

Copy link
Copy Markdown
Contributor

Summary

  • Creates infrastructure/storage.tf using cnp-module-storage-account@4.x with 3 private containers (artefact, files, publications), grants cath-${env}-mi the Storage Blob Data Contributor role, and writes storageaccount-connection-string / storageaccount-name secrets to both the application KV and bootstrap KV (shared-storageaccount-name in bootstrap)
  • Adds 4 storage account variables to infrastructure/variables.tf with pip-matching defaults (StorageV2, Standard, RAGRS, Cool)
  • Injects AZURE_STORAGE_CONNECTION_STRING and AZURE_STORAGE_ACCOUNT_NAME into apps/api/helm/values.yaml and apps/web/helm/values.yaml via Key Vault secret mounts
  • Adds MANAGED_IDENTITY_CLIENT_ID to both values.template.yaml (stg/prod) and values.preview.template.yaml (PR builds) — dev environment reuses cath-stg-mi client ID (platform ops: set as GitHub Actions dev environment variable)
  • Adds Azurite blob emulator service to docker-compose.yml for local development (port 10000)
  • Documents local storage config in apps/web/.env.example with Azurite well-known connection string

Closes #569

Test plan

  • terraform plan produces no errors against stg
  • PR build deploys successfully with MANAGED_IDENTITY_CLIENT_ID set in the dev GitHub Actions environment
  • Local: docker-compose up azurite starts the emulator; app connects using AZURE_STORAGE_CONNECTION_STRING from .env.example
  • Verify KV secret names in storage.tf match module outputs (storageaccount_primary_connection_string, storageaccount_name) once terraform init is run against cnp-module-storage-account@4.x

🤖 Generated with Claude Code

- Add infrastructure/storage.tf using cnp-module-storage-account@4.x
  with 3 private containers (artefact, files, publications), role
  assignment for cath-${env}-mi, and KV secrets for connection string
  and account name (app KV + bootstrap KV)
- Add storage account variables to infrastructure/variables.tf
- Inject storageaccount-* secrets into api and web Helm values
- Add MANAGED_IDENTITY_CLIENT_ID to stg/prod and preview Helm templates
- Add Azurite blob emulator to docker-compose for local development
- Add AZURE_STORAGE_* vars to apps/web/.env.example

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@junaidiqbalmoj, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 53 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 16f32e6e-d748-4965-8a72-1066efc1c5fc

📥 Commits

Reviewing files that changed from the base of the PR and between 4b0aea1 and 9f10bcf.

📒 Files selected for processing (10)
  • apps/web/.env.example
  • docker-compose.yml
  • docs/tickets/569/plan.md
  • docs/tickets/569/review.md
  • docs/tickets/569/tasks.md
  • docs/tickets/569/ticket.md
  • helm/cath-service/values.preview.template.yaml
  • helm/cath-service/values.template.yaml
  • infrastructure/storage.tf
  • infrastructure/variables.tf
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/569-azure-blob-storage

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

junaidiqbalmoj and others added 2 commits June 18, 2026 15:55
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

🎭 Playwright E2E Test Results

84 tests   52 ✅  5m 54s ⏱️
33 suites  32 💤
 1 files     0 ❌

Results for commit 9f10bcf.

♻️ This comment has been updated with latest results.

The module expects managed_identity_object_id (principal ID) and
role_assignments as list(string) of role names, not a list of objects.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Terraform Plan for ithc

Show Plan
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  + create
  ~ update in-place

Terraform will perform the following actions:

  # azurerm_key_vault_secret.bootstrap_shared_storageaccount_name will be created
  + resource "azurerm_key_vault_secret" "bootstrap_shared_storageaccount_name" {
      + id                      = (known after apply)
      + key_vault_id            = "/subscriptions/ba71a911-e0d6-4776-a1a6-079af1df7139/resourceGroups/cath-bootstrap-ithc-rg/providers/Microsoft.KeyVault/vaults/cath-bootstrap-ithc-kv"
      + name                    = "shared-storageaccount-name"
      + resource_id             = (known after apply)
      + resource_versionless_id = (known after apply)
      + value                   = (sensitive value)
      + value_wo                = (write-only attribute)
      + version                 = (known after apply)
      + versionless_id          = (known after apply)
    }

  # azurerm_key_vault_secret.bootstrap_storageaccount_connection_string will be created
  + resource "azurerm_key_vault_secret" "bootstrap_storageaccount_connection_string" {
      + id                      = (known after apply)
      + key_vault_id            = "/subscriptions/ba71a911-e0d6-4776-a1a6-079af1df7139/resourceGroups/cath-bootstrap-ithc-rg/providers/Microsoft.KeyVault/vaults/cath-bootstrap-ithc-kv"
      + name                    = "storageaccount-connection-string"
      + resource_id             = (known after apply)
      + resource_versionless_id = (known after apply)
      + value                   = (sensitive value)
      + value_wo                = (write-only attribute)
      + version                 = (known after apply)
      + versionless_id          = (known after apply)
    }

  # azurerm_key_vault_secret.storageaccount_connection_string will be created
  + resource "azurerm_key_vault_secret" "storageaccount_connection_string" {
      + id                      = (known after apply)
      + key_vault_id            = "/subscriptions/ba71a911-e0d6-4776-a1a6-079af1df7139/resourceGroups/cath-ss-kv-ithc-rg/providers/Microsoft.KeyVault/vaults/cath-ss-kv-ithc"
      + name                    = "storageaccount-connection-string"
      + resource_id             = (known after apply)
      + resource_versionless_id = (known after apply)
      + value                   = (sensitive value)
      + value_wo                = (write-only attribute)
      + version                 = (known after apply)
      + versionless_id          = (known after apply)
    }

  # azurerm_key_vault_secret.storageaccount_name will be created
  + resource "azurerm_key_vault_secret" "storageaccount_name" {
      + id                      = (known after apply)
      + key_vault_id            = "/subscriptions/ba71a911-e0d6-4776-a1a6-079af1df7139/resourceGroups/cath-ss-kv-ithc-rg/providers/Microsoft.KeyVault/vaults/cath-ss-kv-ithc"
      + name                    = "storageaccount-name"
      + resource_id             = (known after apply)
      + resource_versionless_id = (known after apply)
      + value                   = (sensitive value)
      + value_wo                = (write-only attribute)
      + version                 = (known after apply)
      + versionless_id          = (known after apply)
    }

  # module.redis.azurerm_redis_cache.redis will be updated in-place
  ~ resource "azurerm_redis_cache" "redis" {
        id                                 = "/subscriptions/ba71a911-e0d6-4776-a1a6-079af1df7139/resourceGroups/cath-cache-ithc/providers/Microsoft.Cache/redis/cath-redis-ithc"
        name                               = "cath-redis-ithc"
        tags                               = {
            "application"  = "cath"
            "builtFrom"    = "hmcts/cath-service"
            "businessArea" = "Cross-Cutting"
            "environment"  = "ithc"
            "managedBy"    = "cath"
        }
        # (24 unchanged attributes hidden)

      ~ redis_configuration {
          ~ maxfragmentationmemory_reserved         = 30 -> 642
          ~ maxmemory_delta                         = 30 -> 642
          ~ maxmemory_reserved                      = 30 -> 642
            # (14 unchanged attributes hidden)
        }
    }

  # module.sa.azapi_update_resource.defender_settings will be created
  + resource "azapi_update_resource" "defender_settings" {
      + body                    = {
          + properties = {
              + isEnabled                         = false
              + malwareScanning                   = {
                  + onUpload = {
                      + capGBPerMonth = -1
                      + isEnabled     = false
                    }
                }
              + overrideSubscriptionLevelSettings = true
              + sensitiveDataDiscovery            = {
                  + isEnabled = false
                }
            }
        }
      + id                      = (known after apply)
      + ignore_casing           = false
      + ignore_missing_property = true
      + name                    = "current"
      + output                  = (known after apply)
      + parent_id               = (known after apply)
      + resource_id             = (known after apply)
      + sensitive_body          = (write-only attribute)
      + type                    = "Microsoft.Security/DefenderForStorageSettings@2022-12-01-preview"
    }

  # module.sa.azurerm_role_assignment.storage-account-role-assignment["Storage Blob Data Contributor"] will be created
  + resource "azurerm_role_assignment" "storage-account-role-assignment" {
      + condition_version                = (known after apply)
      + id                               = (known after apply)
      + name                             = (known after apply)
      + principal_id                     = "60a2fc5b-1c43-4645-98c4-d63b73868230"
      + principal_type                   = (known after apply)
      + role_definition_id               = (known after apply)
      + role_definition_name             = "Storage Blob Data Contributor"
      + scope                            = (known after apply)
      + skip_service_principal_aad_check = (known after apply)
    }

  # module.sa.azurerm_storage_account.storage_account will be created
  + resource "azurerm_storage_account" "storage_account" {
      + access_tier                        = "Cool"
      + account_kind                       = "StorageV2"
      + account_replication_type           = "RAGRS"
      + account_tier                       = "Standard"
      + allow_nested_items_to_be_public    = false
      + cross_tenant_replication_enabled   = false
      + default_to_oauth_authentication    = false
      + dns_endpoint_type                  = "Standard"
      + https_traffic_only_enabled         = true
      + id                                 = (known after apply)
      + infrastructure_encryption_enabled  = false
      + is_hns_enabled                     = false
      + large_file_share_enabled           = (known after apply)
      + local_user_enabled                 = true
      + location                           = "uksouth"
      + min_tls_version                    = "TLS1_2"
      + name                               = "cathsaithc"
      + nfsv3_enabled                      = false
      + primary_access_key                 = (sensitive value)
      + primary_blob_connection_string     = (sensitive value)
      + primary_blob_endpoint              = (known after apply)
      + primary_blob_host                  = (known after apply)
      + primary_blob_internet_endpoint     = (known after apply)
      + primary_blob_internet_host         = (known after apply)
      + primary_blob_microsoft_endpoint    = (known after apply)
      + primary_blob_microsoft_host        = (known after apply)
      + primary_connection_string          = (sensitive value)
      + primary_dfs_endpoint               = (known after apply)
      + primary_dfs_host                   = (known after apply)
      + primary_dfs_internet_endpoint      = (known after apply)
      + primary_dfs_internet_host          = (known after apply)
      + primary_dfs_microsoft_endpoint     = (known after apply)
      + primary_dfs_microsoft_host         = (known after apply)
      + primary_file_endpoint              = (known after apply)
      + primary_file_host                  = (known after apply)
      + primary_file_internet_endpoint     = (known after apply)
      + primary_file_internet_host         = (known after apply)
      + primary_file_microsoft_endpoint    = (known after apply)
      + primary_file_microsoft_host        = (known after apply)
      + primary_location                   = (known after apply)
      + primary_queue_endpoint             = (known after apply)
      + primary_queue_host                 = (known after apply)
      + primary_queue_microsoft_endpoint   = (known after apply)
      + primary_queue_microsoft_host       = (known after apply)
      + primary_table_endpoint             = (known after apply)
      + primary_table_host                 = (known after apply)
      + primary_table_microsoft_endpoint   = (known after apply)
      + primary_table_microsoft_host       = (known after apply)
      + primary_web_endpoint               = (known after apply)
      + primary_web_host                   = (known after apply)
      + primary_web_internet_endpoint      = (known after apply)
      + primary_web_internet_host          = (known after apply)
      + primary_web_microsoft_endpoint     = (known after apply)
      + primary_web_microsoft_host         = (known after apply)
      + public_network_access_enabled      = true
      + queue_encryption_key_type          = "Service"
      + resource_group_name                = "cath-ithc"
      + secondary_access_key               = (sensitive value)
      + secondary_blob_connection_string   = (sensitive value)
      + secondary_blob_endpoint            = (known after apply)
      + secondary_blob_host                = (known after apply)
      + secondary_blob_internet_endpoint   = (known after apply)
      + secondary_blob_internet_host       = (known after apply)
      + secondary_blob_microsoft_endpoint  = (known after apply)
      + secondary_blob_microsoft_host      = (known after apply)
      + secondary_connection_string        = (sensitive value)
      + secondary_dfs_endpoint             = (known after apply)
      + secondary_dfs_host                 = (known after apply)
      + secondary_dfs_internet_endpoint    = (known after apply)
      + secondary_dfs_internet_host        = (known after apply)
      + secondary_dfs_microsoft_endpoint   = (known after apply)
      + secondary_dfs_microsoft_host       = (known after apply)
      + secondary_file_endpoint            = (known after apply)
      + secondary_file_host                = (known after apply)
      + secondary_file_internet_endpoint   = (known after apply)
      + secondary_file_internet_host       = (known after apply)
      + secondary_file_microsoft_endpoint  = (known after apply)
      + secondary_file_microsoft_host      = (known after apply)
      + secondary_location                 = (known after apply)
      + secondary_queue_endpoint           = (known after apply)
      + secondary_queue_host               = (known after apply)
      + secondary_queue_microsoft_endpoint = (known after apply)
      + secondary_queue_microsoft_host     = (known after apply)
      + secondary_table_endpoint           = (known after apply)
      + secondary_table_host               = (known after apply)
      + secondary_table_microsoft_endpoint = (known after apply)
      + secondary_table_microsoft_host     = (known after apply)
      + secondary_web_endpoint             = (known after apply)
      + secondary_web_host                 = (known after apply)
      + secondary_web_internet_endpoint    = (known after apply)
      + secondary_web_internet_host        = (known after apply)
      + secondary_web_microsoft_endpoint   = (known after apply)
      + secondary_web_microsoft_host       = (known after apply)
      + sftp_enabled                       = false
      + shared_access_key_enabled          = true
      + table_encryption_key_type          = "Service"
      + tags                               = {
          + "application"  = "cath"
          + "builtFrom"    = "hmcts/cath-service"
          + "businessArea" = "Cross-Cutting"
          + "environment"  = "ithc"
          + "managedBy"    = "cath"
        }

      + blob_properties (known after apply)

      + network_rules {
          + bypass                     = [
              + "AzureServices",
            ]
          + default_action             = "Deny"
          + ip_rules                   = (known after apply)
          + virtual_network_subnet_ids = (known after apply)
        }

      + queue_properties (known after apply)

      + routing (known after apply)

      + share_properties (known after apply)

      + static_website (known after apply)
    }

  # module.sa.azurerm_storage_container.container["artefact"] will be created
  + resource "azurerm_storage_container" "container" {
      + container_access_type             = "private"
      + default_encryption_scope          = (known after apply)
      + encryption_scope_override_enabled = true
      + has_immutability_policy           = (known after apply)
      + has_legal_hold                    = (known after apply)
      + id                                = (known after apply)
      + metadata                          = (known after apply)
      + name                              = "artefact"
      + resource_manager_id               = (known after apply)
      + storage_account_name              = "cathsaithc"
    }

  # module.sa.azurerm_storage_container.container["files"] will be created
  + resource "azurerm_storage_container" "container" {
      + container_access_type             = "private"
      + default_encryption_scope          = (known after apply)
      + encryption_scope_override_enabled = true
      + has_immutability_policy           = (known after apply)
      + has_legal_hold                    = (known after apply)
      + id                                = (known after apply)
      + metadata                          = (known after apply)
      + name                              = "files"
      + resource_manager_id               = (known after apply)
      + storage_account_name              = "cathsaithc"
    }

  # module.sa.azurerm_storage_container.container["publications"] will be created
  + resource "azurerm_storage_container" "container" {
      + container_access_type             = "private"
      + default_encryption_scope          = (known after apply)
      + encryption_scope_override_enabled = true
      + has_immutability_policy           = (known after apply)
      + has_legal_hold                    = (known after apply)
      + id                                = (known after apply)
      + metadata                          = (known after apply)
      + name                              = "publications"
      + resource_manager_id               = (known after apply)
      + storage_account_name              = "cathsaithc"
    }

  # module.sa.random_string.storage_account_random_string will be created
  + resource "random_string" "storage_account_random_string" {
      + id          = (known after apply)
      + length      = 24
      + lower       = true
      + min_lower   = 0
      + min_numeric = 0
      + min_special = 0
      + min_upper   = 0
      + number      = true
      + numeric     = true
      + result      = (known after apply)
      + special     = false
      + upper       = false
    }

  # module.sa.time_static.pim_start will be created
  + resource "time_static" "pim_start" {
      + day     = (known after apply)
      + hour    = (known after apply)
      + id      = (known after apply)
      + minute  = (known after apply)
      + month   = (known after apply)
      + rfc3339 = (known after apply)
      + second  = (known after apply)
      + unix    = (known after apply)
      + year    = (known after apply)
    }

Plan: 12 to add, 1 to change, 0 to destroy.

@github-actions

Copy link
Copy Markdown
Contributor

Terraform Plan for demo

Show Plan
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  + create
  ~ update in-place

Terraform will perform the following actions:

  # azurerm_key_vault_secret.bootstrap_shared_storageaccount_name will be created
  + resource "azurerm_key_vault_secret" "bootstrap_shared_storageaccount_name" {
      + id                      = (known after apply)
      + key_vault_id            = "/subscriptions/c68a4bed-4c3d-4956-af51-4ae164c1957c/resourceGroups/cath-bootstrap-demo-rg/providers/Microsoft.KeyVault/vaults/cath-bootstrap-demo-kv"
      + name                    = "shared-storageaccount-name"
      + resource_id             = (known after apply)
      + resource_versionless_id = (known after apply)
      + value                   = (sensitive value)
      + value_wo                = (write-only attribute)
      + version                 = (known after apply)
      + versionless_id          = (known after apply)
    }

  # azurerm_key_vault_secret.bootstrap_storageaccount_connection_string will be created
  + resource "azurerm_key_vault_secret" "bootstrap_storageaccount_connection_string" {
      + id                      = (known after apply)
      + key_vault_id            = "/subscriptions/c68a4bed-4c3d-4956-af51-4ae164c1957c/resourceGroups/cath-bootstrap-demo-rg/providers/Microsoft.KeyVault/vaults/cath-bootstrap-demo-kv"
      + name                    = "storageaccount-connection-string"
      + resource_id             = (known after apply)
      + resource_versionless_id = (known after apply)
      + value                   = (sensitive value)
      + value_wo                = (write-only attribute)
      + version                 = (known after apply)
      + versionless_id          = (known after apply)
    }

  # azurerm_key_vault_secret.storageaccount_connection_string will be created
  + resource "azurerm_key_vault_secret" "storageaccount_connection_string" {
      + id                      = (known after apply)
      + key_vault_id            = "/subscriptions/c68a4bed-4c3d-4956-af51-4ae164c1957c/resourceGroups/cath-ss-kv-demo-rg/providers/Microsoft.KeyVault/vaults/cath-ss-kv-demo"
      + name                    = "storageaccount-connection-string"
      + resource_id             = (known after apply)
      + resource_versionless_id = (known after apply)
      + value                   = (sensitive value)
      + value_wo                = (write-only attribute)
      + version                 = (known after apply)
      + versionless_id          = (known after apply)
    }

  # azurerm_key_vault_secret.storageaccount_name will be created
  + resource "azurerm_key_vault_secret" "storageaccount_name" {
      + id                      = (known after apply)
      + key_vault_id            = "/subscriptions/c68a4bed-4c3d-4956-af51-4ae164c1957c/resourceGroups/cath-ss-kv-demo-rg/providers/Microsoft.KeyVault/vaults/cath-ss-kv-demo"
      + name                    = "storageaccount-name"
      + resource_id             = (known after apply)
      + resource_versionless_id = (known after apply)
      + value                   = (sensitive value)
      + value_wo                = (write-only attribute)
      + version                 = (known after apply)
      + versionless_id          = (known after apply)
    }

  # module.redis.azurerm_redis_cache.redis will be updated in-place
  ~ resource "azurerm_redis_cache" "redis" {
        id                                 = "/subscriptions/c68a4bed-4c3d-4956-af51-4ae164c1957c/resourceGroups/cath-cache-demo/providers/Microsoft.Cache/redis/cath-redis-demo"
        name                               = "cath-redis-demo"
        tags                               = {
            "application"  = "cath"
            "builtFrom"    = "hmcts/cath-service"
            "businessArea" = "Cross-Cutting"
            "environment"  = "demo"
            "managedBy"    = "cath"
        }
        # (24 unchanged attributes hidden)

      ~ redis_configuration {
          ~ maxfragmentationmemory_reserved         = 30 -> 642
          ~ maxmemory_delta                         = 30 -> 642
          ~ maxmemory_reserved                      = 30 -> 642
            # (14 unchanged attributes hidden)
        }
    }

  # module.sa.azapi_update_resource.defender_settings will be created
  + resource "azapi_update_resource" "defender_settings" {
      + body                    = {
          + properties = {
              + isEnabled                         = false
              + malwareScanning                   = {
                  + onUpload = {
                      + capGBPerMonth = -1
                      + isEnabled     = false
                    }
                }
              + overrideSubscriptionLevelSettings = true
              + sensitiveDataDiscovery            = {
                  + isEnabled = false
                }
            }
        }
      + id                      = (known after apply)
      + ignore_casing           = false
      + ignore_missing_property = true
      + name                    = "current"
      + output                  = (known after apply)
      + parent_id               = (known after apply)
      + resource_id             = (known after apply)
      + sensitive_body          = (write-only attribute)
      + type                    = "Microsoft.Security/DefenderForStorageSettings@2022-12-01-preview"
    }

  # module.sa.azurerm_role_assignment.storage-account-role-assignment["Storage Blob Data Contributor"] will be created
  + resource "azurerm_role_assignment" "storage-account-role-assignment" {
      + condition_version                = (known after apply)
      + id                               = (known after apply)
      + name                             = (known after apply)
      + principal_id                     = "2661c8d0-2f43-43e7-9566-a2134d4c181c"
      + principal_type                   = (known after apply)
      + role_definition_id               = (known after apply)
      + role_definition_name             = "Storage Blob Data Contributor"
      + scope                            = (known after apply)
      + skip_service_principal_aad_check = (known after apply)
    }

  # module.sa.azurerm_storage_account.storage_account will be created
  + resource "azurerm_storage_account" "storage_account" {
      + access_tier                        = "Cool"
      + account_kind                       = "StorageV2"
      + account_replication_type           = "RAGRS"
      + account_tier                       = "Standard"
      + allow_nested_items_to_be_public    = false
      + cross_tenant_replication_enabled   = false
      + default_to_oauth_authentication    = false
      + dns_endpoint_type                  = "Standard"
      + https_traffic_only_enabled         = true
      + id                                 = (known after apply)
      + infrastructure_encryption_enabled  = false
      + is_hns_enabled                     = false
      + large_file_share_enabled           = (known after apply)
      + local_user_enabled                 = true
      + location                           = "uksouth"
      + min_tls_version                    = "TLS1_2"
      + name                               = "cathsademo"
      + nfsv3_enabled                      = false
      + primary_access_key                 = (sensitive value)
      + primary_blob_connection_string     = (sensitive value)
      + primary_blob_endpoint              = (known after apply)
      + primary_blob_host                  = (known after apply)
      + primary_blob_internet_endpoint     = (known after apply)
      + primary_blob_internet_host         = (known after apply)
      + primary_blob_microsoft_endpoint    = (known after apply)
      + primary_blob_microsoft_host        = (known after apply)
      + primary_connection_string          = (sensitive value)
      + primary_dfs_endpoint               = (known after apply)
      + primary_dfs_host                   = (known after apply)
      + primary_dfs_internet_endpoint      = (known after apply)
      + primary_dfs_internet_host          = (known after apply)
      + primary_dfs_microsoft_endpoint     = (known after apply)
      + primary_dfs_microsoft_host         = (known after apply)
      + primary_file_endpoint              = (known after apply)
      + primary_file_host                  = (known after apply)
      + primary_file_internet_endpoint     = (known after apply)
      + primary_file_internet_host         = (known after apply)
      + primary_file_microsoft_endpoint    = (known after apply)
      + primary_file_microsoft_host        = (known after apply)
      + primary_location                   = (known after apply)
      + primary_queue_endpoint             = (known after apply)
      + primary_queue_host                 = (known after apply)
      + primary_queue_microsoft_endpoint   = (known after apply)
      + primary_queue_microsoft_host       = (known after apply)
      + primary_table_endpoint             = (known after apply)
      + primary_table_host                 = (known after apply)
      + primary_table_microsoft_endpoint   = (known after apply)
      + primary_table_microsoft_host       = (known after apply)
      + primary_web_endpoint               = (known after apply)
      + primary_web_host                   = (known after apply)
      + primary_web_internet_endpoint      = (known after apply)
      + primary_web_internet_host          = (known after apply)
      + primary_web_microsoft_endpoint     = (known after apply)
      + primary_web_microsoft_host         = (known after apply)
      + public_network_access_enabled      = true
      + queue_encryption_key_type          = "Service"
      + resource_group_name                = "cath-demo"
      + secondary_access_key               = (sensitive value)
      + secondary_blob_connection_string   = (sensitive value)
      + secondary_blob_endpoint            = (known after apply)
      + secondary_blob_host                = (known after apply)
      + secondary_blob_internet_endpoint   = (known after apply)
      + secondary_blob_internet_host       = (known after apply)
      + secondary_blob_microsoft_endpoint  = (known after apply)
      + secondary_blob_microsoft_host      = (known after apply)
      + secondary_connection_string        = (sensitive value)
      + secondary_dfs_endpoint             = (known after apply)
      + secondary_dfs_host                 = (known after apply)
      + secondary_dfs_internet_endpoint    = (known after apply)
      + secondary_dfs_internet_host        = (known after apply)
      + secondary_dfs_microsoft_endpoint   = (known after apply)
      + secondary_dfs_microsoft_host       = (known after apply)
      + secondary_file_endpoint            = (known after apply)
      + secondary_file_host                = (known after apply)
      + secondary_file_internet_endpoint   = (known after apply)
      + secondary_file_internet_host       = (known after apply)
      + secondary_file_microsoft_endpoint  = (known after apply)
      + secondary_file_microsoft_host      = (known after apply)
      + secondary_location                 = (known after apply)
      + secondary_queue_endpoint           = (known after apply)
      + secondary_queue_host               = (known after apply)
      + secondary_queue_microsoft_endpoint = (known after apply)
      + secondary_queue_microsoft_host     = (known after apply)
      + secondary_table_endpoint           = (known after apply)
      + secondary_table_host               = (known after apply)
      + secondary_table_microsoft_endpoint = (known after apply)
      + secondary_table_microsoft_host     = (known after apply)
      + secondary_web_endpoint             = (known after apply)
      + secondary_web_host                 = (known after apply)
      + secondary_web_internet_endpoint    = (known after apply)
      + secondary_web_internet_host        = (known after apply)
      + secondary_web_microsoft_endpoint   = (known after apply)
      + secondary_web_microsoft_host       = (known after apply)
      + sftp_enabled                       = false
      + shared_access_key_enabled          = true
      + table_encryption_key_type          = "Service"
      + tags                               = {
          + "application"  = "cath"
          + "builtFrom"    = "hmcts/cath-service"
          + "businessArea" = "Cross-Cutting"
          + "environment"  = "demo"
          + "managedBy"    = "cath"
        }

      + blob_properties (known after apply)

      + network_rules {
          + bypass                     = [
              + "AzureServices",
            ]
          + default_action             = "Deny"
          + ip_rules                   = (known after apply)
          + virtual_network_subnet_ids = (known after apply)
        }

      + queue_properties (known after apply)

      + routing (known after apply)

      + share_properties (known after apply)

      + static_website (known after apply)
    }

  # module.sa.azurerm_storage_container.container["artefact"] will be created
  + resource "azurerm_storage_container" "container" {
      + container_access_type             = "private"
      + default_encryption_scope          = (known after apply)
      + encryption_scope_override_enabled = true
      + has_immutability_policy           = (known after apply)
      + has_legal_hold                    = (known after apply)
      + id                                = (known after apply)
      + metadata                          = (known after apply)
      + name                              = "artefact"
      + resource_manager_id               = (known after apply)
      + storage_account_name              = "cathsademo"
    }

  # module.sa.azurerm_storage_container.container["files"] will be created
  + resource "azurerm_storage_container" "container" {
      + container_access_type             = "private"
      + default_encryption_scope          = (known after apply)
      + encryption_scope_override_enabled = true
      + has_immutability_policy           = (known after apply)
      + has_legal_hold                    = (known after apply)
      + id                                = (known after apply)
      + metadata                          = (known after apply)
      + name                              = "files"
      + resource_manager_id               = (known after apply)
      + storage_account_name              = "cathsademo"
    }

  # module.sa.azurerm_storage_container.container["publications"] will be created
  + resource "azurerm_storage_container" "container" {
      + container_access_type             = "private"
      + default_encryption_scope          = (known after apply)
      + encryption_scope_override_enabled = true
      + has_immutability_policy           = (known after apply)
      + has_legal_hold                    = (known after apply)
      + id                                = (known after apply)
      + metadata                          = (known after apply)
      + name                              = "publications"
      + resource_manager_id               = (known after apply)
      + storage_account_name              = "cathsademo"
    }

  # module.sa.random_string.storage_account_random_string will be created
  + resource "random_string" "storage_account_random_string" {
      + id          = (known after apply)
      + length      = 24
      + lower       = true
      + min_lower   = 0
      + min_numeric = 0
      + min_special = 0
      + min_upper   = 0
      + number      = true
      + numeric     = true
      + result      = (known after apply)
      + special     = false
      + upper       = false
    }

  # module.sa.time_static.pim_start will be created
  + resource "time_static" "pim_start" {
      + day     = (known after apply)
      + hour    = (known after apply)
      + id      = (known after apply)
      + minute  = (known after apply)
      + month   = (known after apply)
      + rfc3339 = (known after apply)
      + second  = (known after apply)
      + unix    = (known after apply)
      + year    = (known after apply)
    }

Plan: 12 to add, 1 to change, 0 to destroy.

@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Terraform Plan for test

Show Plan
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  + create
  ~ update in-place
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # azurerm_key_vault_secret.bootstrap_shared_storageaccount_name will be created
  + resource "azurerm_key_vault_secret" "bootstrap_shared_storageaccount_name" {
      + id                      = (known after apply)
      + key_vault_id            = "/subscriptions/3eec5bde-7feb-4566-bfb6-805df6e10b90/resourceGroups/cath-bootstrap-test-rg/providers/Microsoft.KeyVault/vaults/cath-bootstrap-test-kv"
      + name                    = "shared-storageaccount-name"
      + resource_id             = (known after apply)
      + resource_versionless_id = (known after apply)
      + value                   = (sensitive value)
      + value_wo                = (write-only attribute)
      + version                 = (known after apply)
      + versionless_id          = (known after apply)
    }

  # azurerm_key_vault_secret.bootstrap_storageaccount_connection_string will be created
  + resource "azurerm_key_vault_secret" "bootstrap_storageaccount_connection_string" {
      + id                      = (known after apply)
      + key_vault_id            = "/subscriptions/3eec5bde-7feb-4566-bfb6-805df6e10b90/resourceGroups/cath-bootstrap-test-rg/providers/Microsoft.KeyVault/vaults/cath-bootstrap-test-kv"
      + name                    = "storageaccount-connection-string"
      + resource_id             = (known after apply)
      + resource_versionless_id = (known after apply)
      + value                   = (sensitive value)
      + value_wo                = (write-only attribute)
      + version                 = (known after apply)
      + versionless_id          = (known after apply)
    }

  # azurerm_key_vault_secret.postgres_host will be updated in-place
  ~ resource "azurerm_key_vault_secret" "postgres_host" {
        id                      = "https://cath-ss-kv-test.vault.azure.net/secrets/postgres-host/424ce46b010c48bbbbb6a1d8c017ff4e"
        name                    = "postgres-host"
        tags                    = {}
      ~ value                   = (sensitive value)
        # (10 unchanged attributes hidden)
    }

  # azurerm_key_vault_secret.postgres_password will be updated in-place
  ~ resource "azurerm_key_vault_secret" "postgres_password" {
        id                      = "https://cath-ss-kv-test.vault.azure.net/secrets/postgres-password/2f46400a520940f0b8a00ba2695101e3"
        name                    = "postgres-password"
        tags                    = {}
      ~ value                   = (sensitive value)
        # (10 unchanged attributes hidden)
    }

  # azurerm_key_vault_secret.postgres_url will be updated in-place
  ~ resource "azurerm_key_vault_secret" "postgres_url" {
        id                      = "https://cath-ss-kv-test.vault.azure.net/secrets/postgres-url/8707332a4180474a8f1e0d4ab4c9af32"
        name                    = "postgres-url"
        tags                    = {}
      ~ value                   = (sensitive value)
        # (10 unchanged attributes hidden)
    }

  # azurerm_key_vault_secret.storageaccount_connection_string will be created
  + resource "azurerm_key_vault_secret" "storageaccount_connection_string" {
      + id                      = (known after apply)
      + key_vault_id            = "/subscriptions/3eec5bde-7feb-4566-bfb6-805df6e10b90/resourceGroups/cath-ss-kv-test-rg/providers/Microsoft.KeyVault/vaults/cath-ss-kv-test"
      + name                    = "storageaccount-connection-string"
      + resource_id             = (known after apply)
      + resource_versionless_id = (known after apply)
      + value                   = (sensitive value)
      + value_wo                = (write-only attribute)
      + version                 = (known after apply)
      + versionless_id          = (known after apply)
    }

  # azurerm_key_vault_secret.storageaccount_name will be created
  + resource "azurerm_key_vault_secret" "storageaccount_name" {
      + id                      = (known after apply)
      + key_vault_id            = "/subscriptions/3eec5bde-7feb-4566-bfb6-805df6e10b90/resourceGroups/cath-ss-kv-test-rg/providers/Microsoft.KeyVault/vaults/cath-ss-kv-test"
      + name                    = "storageaccount-name"
      + resource_id             = (known after apply)
      + resource_versionless_id = (known after apply)
      + value                   = (sensitive value)
      + value_wo                = (write-only attribute)
      + version                 = (known after apply)
      + versionless_id          = (known after apply)
    }

  # module.postgresql.azurerm_postgresql_flexible_server.pgsql_server will be created
  + resource "azurerm_postgresql_flexible_server" "pgsql_server" {
      + administrator_login           = "pgadmin"
      + administrator_password        = (sensitive value)
      + administrator_password_wo     = (write-only attribute)
      + auto_grow_enabled             = true
      + backup_retention_days         = 35
      + create_mode                   = "Default"
      + delegated_subnet_id           = "/subscriptions/3eec5bde-7feb-4566-bfb6-805df6e10b90/resourceGroups/ss-test-network-rg/providers/Microsoft.Network/virtualNetworks/ss-test-vnet/subnets/postgres-expanded"
      + fqdn                          = (known after apply)
      + geo_redundant_backup_enabled  = false
      + id                            = (known after apply)
      + location                      = "uksouth"
      + name                          = "flexible-cath-test"
      + private_dns_zone_id           = "/subscriptions/1baf5470-1c3e-40d3-a6f7-74bfbce4b348/resourceGroups/core-infra-intsvc-rg/providers/Microsoft.Network/privateDnsZones/private.postgres.database.azure.com"
      + public_network_access_enabled = false
      + resource_group_name           = "flexible-cath-test-rg"
      + sku_name                      = "GP_Standard_D2ds_v4"
      + storage_mb                    = 65536
      + storage_tier                  = (known after apply)
      + tags                          = {
          + "application"  = "cath"
          + "builtFrom"    = "hmcts/cath-service"
          + "businessArea" = "Cross-Cutting"
          + "environment"  = "testing"
          + "managedBy"    = "cath"
        }
      + version                       = "16"

      + authentication {
          + active_directory_auth_enabled = true
          + password_auth_enabled         = true
          + tenant_id                     = "531ff96d-0ae9-462a-8d2d-bec7c0b42082"
        }

      + high_availability {
          + mode = "ZoneRedundant"
        }

      + maintenance_window {
          + day_of_week  = 0
          + start_hour   = 3
          + start_minute = 0
        }
    }

  # module.postgresql.azurerm_postgresql_flexible_server_active_directory_administrator.pgsql_adadmin will be created
  + resource "azurerm_postgresql_flexible_server_active_directory_administrator" "pgsql_adadmin" {
      + id                  = (known after apply)
      + object_id           = "3c52c98b-07a3-4a97-92b9-298e86bb1ca9"
      + principal_name      = "DTS Platform Operations PostgreSQL Admin Access"
      + principal_type      = "Group"
      + resource_group_name = "flexible-cath-test-rg"
      + server_name         = "flexible-cath-test"
      + tenant_id           = "531ff96d-0ae9-462a-8d2d-bec7c0b42082"
    }

  # module.postgresql.azurerm_postgresql_flexible_server_active_directory_administrator.pgsql_principal_admin[0] will be created
  + resource "azurerm_postgresql_flexible_server_active_directory_administrator" "pgsql_principal_admin" {
      + id                  = (known after apply)
      + object_id           = "69aa7255-12ea-45a3-af45-e9d249cddfe0"
      + principal_name      = "cath-service"
      + principal_type      = "ServicePrincipal"
      + resource_group_name = "flexible-cath-test-rg"
      + server_name         = "flexible-cath-test"
      + tenant_id           = "531ff96d-0ae9-462a-8d2d-bec7c0b42082"
    }

  # module.postgresql.azurerm_postgresql_flexible_server_configuration.pgsql_server_config["backslash_quote"] must be replaced
-/+ resource "azurerm_postgresql_flexible_server_configuration" "pgsql_server_config" {
      ~ id        = "/subscriptions/3eec5bde-7feb-4566-bfb6-805df6e10b90/resourceGroups/flexible-cath-test-rg/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexible-cath-test/configurations/backslash_quote" -> (known after apply)
        name      = "backslash_quote"
      ~ server_id = "/subscriptions/3eec5bde-7feb-4566-bfb6-805df6e10b90/resourceGroups/flexible-cath-test-rg/providers/Microsoft.DBforPostgreSQL/flexibleServers/flexible-cath-test" -> (known after apply) # forces replacement
        # (1 unchanged attribute hidden)
    }

  # module.postgresql.azurerm_postgresql_flexible_server_database.pg_databases["cath"] will be created
  + resource "azurerm_postgresql_flexible_server_database" "pg_databases" {
      + charset   = "utf8"
      + collation = "en_GB.utf8"
      + id        = (known after apply)
      + name      = "cath"
      + server_id = (known after apply)
    }

  # module.postgresql.random_password.password will be created
  + resource "random_password" "password" {
      + bcrypt_hash      = (sensitive value)
      + id               = (known after apply)
      + length           = 20
      + lower            = true
      + min_lower        = 0
      + min_numeric      = 0
      + min_special      = 0
      + min_upper        = 0
      + number           = true
      + numeric          = true
      + override_special = "()-_"
      + result           = (sensitive value)
      + special          = true
      + upper            = true
    }

  # module.postgresql.terraform_data.trigger_password_reset will be created
  + resource "terraform_data" "trigger_password_reset" {
      + id     = (known after apply)
      + input  = ""
      + output = (known after apply)
    }

  # module.redis.azurerm_redis_cache.redis will be updated in-place
  ~ resource "azurerm_redis_cache" "redis" {
        id                                 = "/subscriptions/3eec5bde-7feb-4566-bfb6-805df6e10b90/resourceGroups/cath-cache-test/providers/Microsoft.Cache/redis/cath-redis-test"
        name                               = "cath-redis-test"
        tags                               = {
            "application"  = "cath"
            "builtFrom"    = "hmcts/cath-service"
            "businessArea" = "Cross-Cutting"
            "environment"  = "testing"
            "managedBy"    = "cath"
        }
        # (24 unchanged attributes hidden)

      ~ redis_configuration {
          ~ maxfragmentationmemory_reserved         = 30 -> 642
          ~ maxmemory_delta                         = 30 -> 642
          ~ maxmemory_reserved                      = 30 -> 642
            # (14 unchanged attributes hidden)
        }
    }

  # module.sa.azapi_update_resource.defender_settings will be created
  + resource "azapi_update_resource" "defender_settings" {
      + body                    = {
          + properties = {
              + isEnabled                         = false
              + malwareScanning                   = {
                  + onUpload = {
                      + capGBPerMonth = -1
                      + isEnabled     = false
                    }
                }
              + overrideSubscriptionLevelSettings = true
              + sensitiveDataDiscovery            = {
                  + isEnabled = false
                }
            }
        }
      + id                      = (known after apply)
      + ignore_casing           = false
      + ignore_missing_property = true
      + name                    = "current"
      + output                  = (known after apply)
      + parent_id               = (known after apply)
      + resource_id             = (known after apply)
      + sensitive_body          = (write-only attribute)
      + type                    = "Microsoft.Security/DefenderForStorageSettings@2022-12-01-preview"
    }

  # module.sa.azurerm_role_assignment.storage-account-role-assignment["Storage Blob Data Contributor"] will be created
  + resource "azurerm_role_assignment" "storage-account-role-assignment" {
      + condition_version                = (known after apply)
      + id                               = (known after apply)
      + name                             = (known after apply)
      + principal_id                     = "c53956b8-622d-472a-bb44-93456d46c180"
      + principal_type                   = (known after apply)
      + role_definition_id               = (known after apply)
      + role_definition_name             = "Storage Blob Data Contributor"
      + scope                            = (known after apply)
      + skip_service_principal_aad_check = (known after apply)
    }

  # module.sa.azurerm_storage_account.storage_account will be created
  + resource "azurerm_storage_account" "storage_account" {
      + access_tier                        = "Cool"
      + account_kind                       = "StorageV2"
      + account_replication_type           = "RAGRS"
      + account_tier                       = "Standard"
      + allow_nested_items_to_be_public    = false
      + cross_tenant_replication_enabled   = false
      + default_to_oauth_authentication    = false
      + dns_endpoint_type                  = "Standard"
      + https_traffic_only_enabled         = true
      + id                                 = (known after apply)
      + infrastructure_encryption_enabled  = false
      + is_hns_enabled                     = false
      + large_file_share_enabled           = (known after apply)
      + local_user_enabled                 = true
      + location                           = "uksouth"
      + min_tls_version                    = "TLS1_2"
      + name                               = "cathsatest"
      + nfsv3_enabled                      = false
      + primary_access_key                 = (sensitive value)
      + primary_blob_connection_string     = (sensitive value)
      + primary_blob_endpoint              = (known after apply)
      + primary_blob_host                  = (known after apply)
      + primary_blob_internet_endpoint     = (known after apply)
      + primary_blob_internet_host         = (known after apply)
      + primary_blob_microsoft_endpoint    = (known after apply)
      + primary_blob_microsoft_host        = (known after apply)
      + primary_connection_string          = (sensitive value)
      + primary_dfs_endpoint               = (known after apply)
      + primary_dfs_host                   = (known after apply)
      + primary_dfs_internet_endpoint      = (known after apply)
      + primary_dfs_internet_host          = (known after apply)
      + primary_dfs_microsoft_endpoint     = (known after apply)
      + primary_dfs_microsoft_host         = (known after apply)
      + primary_file_endpoint              = (known after apply)
      + primary_file_host                  = (known after apply)
      + primary_file_internet_endpoint     = (known after apply)
      + primary_file_internet_host         = (known after apply)
      + primary_file_microsoft_endpoint    = (known after apply)
      + primary_file_microsoft_host        = (known after apply)
      + primary_location                   = (known after apply)
      + primary_queue_endpoint             = (known after apply)
      + primary_queue_host                 = (known after apply)
      + primary_queue_microsoft_endpoint   = (known after apply)
      + primary_queue_microsoft_host       = (known after apply)
      + primary_table_endpoint             = (known after apply)
      + primary_table_host                 = (known after apply)
      + primary_table_microsoft_endpoint   = (known after apply)
      + primary_table_microsoft_host       = (known after apply)
      + primary_web_endpoint               = (known after apply)
      + primary_web_host                   = (known after apply)
      + primary_web_internet_endpoint      = (known after apply)
      + primary_web_internet_host          = (known after apply)
      + primary_web_microsoft_endpoint     = (known after apply)
      + primary_web_microsoft_host         = (known after apply)
      + public_network_access_enabled      = true
      + queue_encryption_key_type          = "Service"
      + resource_group_name                = "cath-test"
      + secondary_access_key               = (sensitive value)
      + secondary_blob_connection_string   = (sensitive value)
      + secondary_blob_endpoint            = (known after apply)
      + secondary_blob_host                = (known after apply)
      + secondary_blob_internet_endpoint   = (known after apply)
      + secondary_blob_internet_host       = (known after apply)
      + secondary_blob_microsoft_endpoint  = (known after apply)
      + secondary_blob_microsoft_host      = (known after apply)
      + secondary_connection_string        = (sensitive value)
      + secondary_dfs_endpoint             = (known after apply)
      + secondary_dfs_host                 = (known after apply)
      + secondary_dfs_internet_endpoint    = (known after apply)
      + secondary_dfs_internet_host        = (known after apply)
      + secondary_dfs_microsoft_endpoint   = (known after apply)
      + secondary_dfs_microsoft_host       = (known after apply)
      + secondary_file_endpoint            = (known after apply)
      + secondary_file_host                = (known after apply)
      + secondary_file_internet_endpoint   = (known after apply)
      + secondary_file_internet_host       = (known after apply)
      + secondary_file_microsoft_endpoint  = (known after apply)
      + secondary_file_microsoft_host      = (known after apply)
      + secondary_location                 = (known after apply)
      + secondary_queue_endpoint           = (known after apply)
      + secondary_queue_host               = (known after apply)
      + secondary_queue_microsoft_endpoint = (known after apply)
      + secondary_queue_microsoft_host     = (known after apply)
      + secondary_table_endpoint           = (known after apply)
      + secondary_table_host               = (known after apply)
      + secondary_table_microsoft_endpoint = (known after apply)
      + secondary_table_microsoft_host     = (known after apply)
      + secondary_web_endpoint             = (known after apply)
      + secondary_web_host                 = (known after apply)
      + secondary_web_internet_endpoint    = (known after apply)
      + secondary_web_internet_host        = (known after apply)
      + secondary_web_microsoft_endpoint   = (known after apply)
      + secondary_web_microsoft_host       = (known after apply)
      + sftp_enabled                       = false
      + shared_access_key_enabled          = true
      + table_encryption_key_type          = "Service"
      + tags                               = {
          + "application"  = "cath"
          + "builtFrom"    = "hmcts/cath-service"
          + "businessArea" = "Cross-Cutting"
          + "environment"  = "testing"
          + "managedBy"    = "cath"
        }

      + blob_properties (known after apply)

      + network_rules {
          + bypass                     = [
              + "AzureServices",
            ]
          + default_action             = "Deny"
          + ip_rules                   = (known after apply)
          + virtual_network_subnet_ids = (known after apply)
        }

      + queue_properties (known after apply)

      + routing (known after apply)

      + share_properties (known after apply)

      + static_website (known after apply)
    }

  # module.sa.azurerm_storage_container.container["artefact"] will be created
  + resource "azurerm_storage_container" "container" {
      + container_access_type             = "private"
      + default_encryption_scope          = (known after apply)
      + encryption_scope_override_enabled = true
      + has_immutability_policy           = (known after apply)
      + has_legal_hold                    = (known after apply)
      + id                                = (known after apply)
      + metadata                          = (known after apply)
      + name                              = "artefact"
      + resource_manager_id               = (known after apply)
      + storage_account_name              = "cathsatest"
    }

  # module.sa.azurerm_storage_container.container["files"] will be created
  + resource "azurerm_storage_container" "container" {
      + container_access_type             = "private"
      + default_encryption_scope          = (known after apply)
      + encryption_scope_override_enabled = true
      + has_immutability_policy           = (known after apply)
      + has_legal_hold                    = (known after apply)
      + id                                = (known after apply)
      + metadata                          = (known after apply)
      + name                              = "files"
      + resource_manager_id               = (known after apply)
      + storage_account_name              = "cathsatest"
    }

  # module.sa.azurerm_storage_container.container["publications"] will be created
  + resource "azurerm_storage_container" "container" {
      + container_access_type             = "private"
      + default_encryption_scope          = (known after apply)
      + encryption_scope_override_enabled = true
      + has_immutability_policy           = (known after apply)
      + has_legal_hold                    = (known after apply)
      + id                                = (known after apply)
      + metadata                          = (known after apply)
      + name                              = "publications"
      + resource_manager_id               = (known after apply)
      + storage_account_name              = "cathsatest"
    }

  # module.sa.random_string.storage_account_random_string will be created
  + resource "random_string" "storage_account_random_string" {
      + id          = (known after apply)
      + length      = 24
      + lower       = true
      + min_lower   = 0
      + min_numeric = 0
      + min_special = 0
      + min_upper   = 0
      + number      = true
      + numeric     = true
      + result      = (known after apply)
      + special     = false
      + upper       = false
    }

  # module.sa.time_static.pim_start will be created
  + resource "time_static" "pim_start" {
      + day     = (known after apply)
      + hour    = (known after apply)
      + id      = (known after apply)
      + minute  = (known after apply)
      + month   = (known after apply)
      + rfc3339 = (known after apply)
      + second  = (known after apply)
      + unix    = (known after apply)
      + year    = (known after apply)
    }

Plan: 19 to add, 4 to change, 1 to destroy.

@github-actions

Copy link
Copy Markdown
Contributor

Terraform Plan for stg

Show Plan
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  + create
  ~ update in-place

Terraform will perform the following actions:

  # azurerm_key_vault_secret.bootstrap_shared_storageaccount_name will be created
  + resource "azurerm_key_vault_secret" "bootstrap_shared_storageaccount_name" {
      + id                      = (known after apply)
      + key_vault_id            = "/subscriptions/74dacd4f-a248-45bb-a2f0-af700dc4cf68/resourceGroups/cath-bootstrap-stg-rg/providers/Microsoft.KeyVault/vaults/cath-bootstrap-stg-kv"
      + name                    = "shared-storageaccount-name"
      + resource_id             = (known after apply)
      + resource_versionless_id = (known after apply)
      + value                   = (sensitive value)
      + value_wo                = (write-only attribute)
      + version                 = (known after apply)
      + versionless_id          = (known after apply)
    }

  # azurerm_key_vault_secret.bootstrap_storageaccount_connection_string will be created
  + resource "azurerm_key_vault_secret" "bootstrap_storageaccount_connection_string" {
      + id                      = (known after apply)
      + key_vault_id            = "/subscriptions/74dacd4f-a248-45bb-a2f0-af700dc4cf68/resourceGroups/cath-bootstrap-stg-rg/providers/Microsoft.KeyVault/vaults/cath-bootstrap-stg-kv"
      + name                    = "storageaccount-connection-string"
      + resource_id             = (known after apply)
      + resource_versionless_id = (known after apply)
      + value                   = (sensitive value)
      + value_wo                = (write-only attribute)
      + version                 = (known after apply)
      + versionless_id          = (known after apply)
    }

  # azurerm_key_vault_secret.storageaccount_connection_string will be created
  + resource "azurerm_key_vault_secret" "storageaccount_connection_string" {
      + id                      = (known after apply)
      + key_vault_id            = "/subscriptions/74dacd4f-a248-45bb-a2f0-af700dc4cf68/resourceGroups/cath-ss-kv-stg-rg/providers/Microsoft.KeyVault/vaults/cath-ss-kv-stg"
      + name                    = "storageaccount-connection-string"
      + resource_id             = (known after apply)
      + resource_versionless_id = (known after apply)
      + value                   = (sensitive value)
      + value_wo                = (write-only attribute)
      + version                 = (known after apply)
      + versionless_id          = (known after apply)
    }

  # azurerm_key_vault_secret.storageaccount_name will be created
  + resource "azurerm_key_vault_secret" "storageaccount_name" {
      + id                      = (known after apply)
      + key_vault_id            = "/subscriptions/74dacd4f-a248-45bb-a2f0-af700dc4cf68/resourceGroups/cath-ss-kv-stg-rg/providers/Microsoft.KeyVault/vaults/cath-ss-kv-stg"
      + name                    = "storageaccount-name"
      + resource_id             = (known after apply)
      + resource_versionless_id = (known after apply)
      + value                   = (sensitive value)
      + value_wo                = (write-only attribute)
      + version                 = (known after apply)
      + versionless_id          = (known after apply)
    }

  # module.redis.azurerm_redis_cache.redis will be updated in-place
  ~ resource "azurerm_redis_cache" "redis" {
        id                                 = "/subscriptions/74dacd4f-a248-45bb-a2f0-af700dc4cf68/resourceGroups/cath-cache-stg/providers/Microsoft.Cache/redis/cath-redis-stg"
        name                               = "cath-redis-stg"
        tags                               = {
            "application"  = "cath"
            "builtFrom"    = "hmcts/cath-service"
            "businessArea" = "Cross-Cutting"
            "environment"  = "staging"
            "managedBy"    = "cath"
        }
        # (24 unchanged attributes hidden)

      ~ redis_configuration {
          ~ maxfragmentationmemory_reserved         = 30 -> 642
          ~ maxmemory_delta                         = 30 -> 642
          ~ maxmemory_reserved                      = 30 -> 642
            # (14 unchanged attributes hidden)
        }
    }

  # module.sa.azapi_update_resource.defender_settings will be created
  + resource "azapi_update_resource" "defender_settings" {
      + body                    = {
          + properties = {
              + isEnabled                         = false
              + malwareScanning                   = {
                  + onUpload = {
                      + capGBPerMonth = -1
                      + isEnabled     = false
                    }
                }
              + overrideSubscriptionLevelSettings = true
              + sensitiveDataDiscovery            = {
                  + isEnabled = false
                }
            }
        }
      + id                      = (known after apply)
      + ignore_casing           = false
      + ignore_missing_property = true
      + name                    = "current"
      + output                  = (known after apply)
      + parent_id               = (known after apply)
      + resource_id             = (known after apply)
      + sensitive_body          = (write-only attribute)
      + type                    = "Microsoft.Security/DefenderForStorageSettings@2022-12-01-preview"
    }

  # module.sa.azurerm_role_assignment.storage-account-role-assignment["Storage Blob Data Contributor"] will be created
  + resource "azurerm_role_assignment" "storage-account-role-assignment" {
      + condition_version                = (known after apply)
      + id                               = (known after apply)
      + name                             = (known after apply)
      + principal_id                     = "db8763ce-0bef-4fe0-9790-390827e15742"
      + principal_type                   = (known after apply)
      + role_definition_id               = (known after apply)
      + role_definition_name             = "Storage Blob Data Contributor"
      + scope                            = (known after apply)
      + skip_service_principal_aad_check = (known after apply)
    }

  # module.sa.azurerm_storage_account.storage_account will be created
  + resource "azurerm_storage_account" "storage_account" {
      + access_tier                        = "Cool"
      + account_kind                       = "StorageV2"
      + account_replication_type           = "RAGRS"
      + account_tier                       = "Standard"
      + allow_nested_items_to_be_public    = false
      + cross_tenant_replication_enabled   = false
      + default_to_oauth_authentication    = false
      + dns_endpoint_type                  = "Standard"
      + https_traffic_only_enabled         = true
      + id                                 = (known after apply)
      + infrastructure_encryption_enabled  = false
      + is_hns_enabled                     = false
      + large_file_share_enabled           = (known after apply)
      + local_user_enabled                 = true
      + location                           = "uksouth"
      + min_tls_version                    = "TLS1_2"
      + name                               = "cathsastg"
      + nfsv3_enabled                      = false
      + primary_access_key                 = (sensitive value)
      + primary_blob_connection_string     = (sensitive value)
      + primary_blob_endpoint              = (known after apply)
      + primary_blob_host                  = (known after apply)
      + primary_blob_internet_endpoint     = (known after apply)
      + primary_blob_internet_host         = (known after apply)
      + primary_blob_microsoft_endpoint    = (known after apply)
      + primary_blob_microsoft_host        = (known after apply)
      + primary_connection_string          = (sensitive value)
      + primary_dfs_endpoint               = (known after apply)
      + primary_dfs_host                   = (known after apply)
      + primary_dfs_internet_endpoint      = (known after apply)
      + primary_dfs_internet_host          = (known after apply)
      + primary_dfs_microsoft_endpoint     = (known after apply)
      + primary_dfs_microsoft_host         = (known after apply)
      + primary_file_endpoint              = (known after apply)
      + primary_file_host                  = (known after apply)
      + primary_file_internet_endpoint     = (known after apply)
      + primary_file_internet_host         = (known after apply)
      + primary_file_microsoft_endpoint    = (known after apply)
      + primary_file_microsoft_host        = (known after apply)
      + primary_location                   = (known after apply)
      + primary_queue_endpoint             = (known after apply)
      + primary_queue_host                 = (known after apply)
      + primary_queue_microsoft_endpoint   = (known after apply)
      + primary_queue_microsoft_host       = (known after apply)
      + primary_table_endpoint             = (known after apply)
      + primary_table_host                 = (known after apply)
      + primary_table_microsoft_endpoint   = (known after apply)
      + primary_table_microsoft_host       = (known after apply)
      + primary_web_endpoint               = (known after apply)
      + primary_web_host                   = (known after apply)
      + primary_web_internet_endpoint      = (known after apply)
      + primary_web_internet_host          = (known after apply)
      + primary_web_microsoft_endpoint     = (known after apply)
      + primary_web_microsoft_host         = (known after apply)
      + public_network_access_enabled      = true
      + queue_encryption_key_type          = "Service"
      + resource_group_name                = "cath-stg"
      + secondary_access_key               = (sensitive value)
      + secondary_blob_connection_string   = (sensitive value)
      + secondary_blob_endpoint            = (known after apply)
      + secondary_blob_host                = (known after apply)
      + secondary_blob_internet_endpoint   = (known after apply)
      + secondary_blob_internet_host       = (known after apply)
      + secondary_blob_microsoft_endpoint  = (known after apply)
      + secondary_blob_microsoft_host      = (known after apply)
      + secondary_connection_string        = (sensitive value)
      + secondary_dfs_endpoint             = (known after apply)
      + secondary_dfs_host                 = (known after apply)
      + secondary_dfs_internet_endpoint    = (known after apply)
      + secondary_dfs_internet_host        = (known after apply)
      + secondary_dfs_microsoft_endpoint   = (known after apply)
      + secondary_dfs_microsoft_host       = (known after apply)
      + secondary_file_endpoint            = (known after apply)
      + secondary_file_host                = (known after apply)
      + secondary_file_internet_endpoint   = (known after apply)
      + secondary_file_internet_host       = (known after apply)
      + secondary_file_microsoft_endpoint  = (known after apply)
      + secondary_file_microsoft_host      = (known after apply)
      + secondary_location                 = (known after apply)
      + secondary_queue_endpoint           = (known after apply)
      + secondary_queue_host               = (known after apply)
      + secondary_queue_microsoft_endpoint = (known after apply)
      + secondary_queue_microsoft_host     = (known after apply)
      + secondary_table_endpoint           = (known after apply)
      + secondary_table_host               = (known after apply)
      + secondary_table_microsoft_endpoint = (known after apply)
      + secondary_table_microsoft_host     = (known after apply)
      + secondary_web_endpoint             = (known after apply)
      + secondary_web_host                 = (known after apply)
      + secondary_web_internet_endpoint    = (known after apply)
      + secondary_web_internet_host        = (known after apply)
      + secondary_web_microsoft_endpoint   = (known after apply)
      + secondary_web_microsoft_host       = (known after apply)
      + sftp_enabled                       = false
      + shared_access_key_enabled          = true
      + table_encryption_key_type          = "Service"
      + tags                               = {
          + "application"  = "cath"
          + "builtFrom"    = "hmcts/cath-service"
          + "businessArea" = "Cross-Cutting"
          + "environment"  = "staging"
          + "managedBy"    = "cath"
        }

      + blob_properties (known after apply)

      + network_rules {
          + bypass                     = [
              + "AzureServices",
            ]
          + default_action             = "Deny"
          + ip_rules                   = (known after apply)
          + virtual_network_subnet_ids = (known after apply)
        }

      + queue_properties (known after apply)

      + routing (known after apply)

      + share_properties (known after apply)

      + static_website (known after apply)
    }

  # module.sa.azurerm_storage_container.container["artefact"] will be created
  + resource "azurerm_storage_container" "container" {
      + container_access_type             = "private"
      + default_encryption_scope          = (known after apply)
      + encryption_scope_override_enabled = true
      + has_immutability_policy           = (known after apply)
      + has_legal_hold                    = (known after apply)
      + id                                = (known after apply)
      + metadata                          = (known after apply)
      + name                              = "artefact"
      + resource_manager_id               = (known after apply)
      + storage_account_name              = "cathsastg"
    }

  # module.sa.azurerm_storage_container.container["files"] will be created
  + resource "azurerm_storage_container" "container" {
      + container_access_type             = "private"
      + default_encryption_scope          = (known after apply)
      + encryption_scope_override_enabled = true
      + has_immutability_policy           = (known after apply)
      + has_legal_hold                    = (known after apply)
      + id                                = (known after apply)
      + metadata                          = (known after apply)
      + name                              = "files"
      + resource_manager_id               = (known after apply)
      + storage_account_name              = "cathsastg"
    }

  # module.sa.azurerm_storage_container.container["publications"] will be created
  + resource "azurerm_storage_container" "container" {
      + container_access_type             = "private"
      + default_encryption_scope          = (known after apply)
      + encryption_scope_override_enabled = true
      + has_immutability_policy           = (known after apply)
      + has_legal_hold                    = (known after apply)
      + id                                = (known after apply)
      + metadata                          = (known after apply)
      + name                              = "publications"
      + resource_manager_id               = (known after apply)
      + storage_account_name              = "cathsastg"
    }

  # module.sa.random_string.storage_account_random_string will be created
  + resource "random_string" "storage_account_random_string" {
      + id          = (known after apply)
      + length      = 24
      + lower       = true
      + min_lower   = 0
      + min_numeric = 0
      + min_special = 0
      + min_upper   = 0
      + number      = true
      + numeric     = true
      + result      = (known after apply)
      + special     = false
      + upper       = false
    }

  # module.sa.time_static.pim_start will be created
  + resource "time_static" "pim_start" {
      + day     = (known after apply)
      + hour    = (known after apply)
      + id      = (known after apply)
      + minute  = (known after apply)
      + month   = (known after apply)
      + rfc3339 = (known after apply)
      + second  = (known after apply)
      + unix    = (known after apply)
      + year    = (known after apply)
    }

Plan: 12 to add, 1 to change, 0 to destroy.

Removes storageaccount-* secrets from base values.yaml files so PR/dev
builds don't hang waiting for secrets that only exist after Terraform
applies. Secrets are now injected via values.template.yaml (stg/prod)
where the storage account will have been provisioned.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment Successful 🚀

Your preview environment is ready:

The environment will be automatically cleaned up when this PR is closed.

@junaidiqbalmoj
junaidiqbalmoj merged commit 575225f into master Jun 19, 2026
35 checks passed
hmctsclaudecode Bot pushed a commit that referenced this pull request Jul 9, 2026
10 STATUS + IMPL changes (closed issue + merged closing PR → verified):
  REQ-0078 (#301): implemented → verified (PR #458)
  REQ-0105 (#428): in_progress  → verified (PR #749)
  REQ-0106 (#429): approved     → verified (PR #761)
  REQ-0107 (#431): implemented → verified (PR #701)
  REQ-0108 (#434): approved     → verified (PR #772)
  REQ-0109 (#436): implemented → verified (PR #727)
  REQ-0112 (#467): implemented → verified (PR #670)
  REQ-0124 (#563): approved     → verified (PR #782)
  REQ-0135 (#569): in_progress  → verified (PR #748)
  REQ-0137 (#729): approved     → verified (PR #766)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Azure Blob Storage to cath-service infrastructure Terraform

2 participants