Skip to main content
Version: Omada Identity Cloud Private

Installation Script mode

This page describes the Installation Script deployment mode for Omada Identity Cloud Private – the recommended and fully supported path for first-time and standard deployments. For an overview of deployment modes and shared prerequisites, see the Deployment guide.

Overview

A single installation script (install.sh) orchestrates the entire deployment end-to-end:

  • Preflight validation: OS, disk space, network connectivity checks.
  • Toolchain bootstrap: Installs Azure CLI, Terraform, Helm, kubectl, kubelogin, skopeo, jq, ODBC Driver 18, Python, and Ansible automatically.
  • Infrastructure provisioning: Terraform backend, shared global infrastructure, and workspace-specific resources.
  • Artifact publishing: Container images to ACR and release artifacts to blob storage.
  • Configuration validation: Key Vault certificate and secret checks before compute provisioning.
  • Node setup: Ansible playbooks for AKS configuration and application deployment.
  • Health check: Automated post-deployment readiness check.

Before starting, make sure the Installation Script prerequisites and Networking prerequisites are in place.

Step 1: Extract the installation package

Omada provides the Omada Identity Cloud Private installation package via SharePoint. When you download it, it will be a .zip file named oicp_install_<version>.zip, where <version> is the release version you are installing.

tip

If unzip isn't already installed (common on minimal VM images), install it first: sudo apt update && sudo apt install -y unzip.

Extract it and navigate to the installation directory:

Tool: Bash shell

unzip oicp_install_<version>.zip
cd scripts/install

Step 2: Configure deployment-config.json

The deployment-config.json file in the installation directory is the single configuration input for the entire deployment. Edit it with your environment-specific values before running the script.

info

You can create multiple named copies of this file (for example, for different environments) and pass the desired one via the optional --config parameter, described later.

Use an absolute path, or a file name with no directory component, placed directly in scripts/install. A relative path with subdirectories (for example, --config ./configs/dev.json) is not honored as given: only the file name is used, resolved against scripts/install, so the file must be stored there under that name.

Key parameters to configure:

SectionParameterDescription
azuresubscription_idAzure subscription GUID.
azuretenant_idAzure AD (Microsoft Entra ID) tenant GUID.
azurelocationAzure region (for example, swedencentral).
deploymentworkspace_prefixWorkspace identifier – 2 lowercase letters + 4 digits (for example, ab0001).
deploymentproject_nameProject name for resource naming (for example, oicp).
deploymentomada_license_stringOmada license key – provided by Omada.
deploymentupdate_private_dns_recordsWhether to update private DNS records automatically. Defaults to true.
backendstorage_account_nameStorage account for Terraform state.
backendcontainer_nameBlob container name for state files.
backendkeyTerraform state file name. Defaults to terraform.tfstate; the shared-infrastructure state is stored as <key>.shared.
releasepackage_urlSecure URL to the Cloud Private release package – provided by Omada. This is a signed, credential-bearing URL – treat it like a password. Don't paste it into chat, tickets, or slides; it expires on its own, but anyone with it can download the package until then. Must contain a /releases/<version>/ path segment, as in the SAS URLs Omada sends – the installer extracts <version> from this segment to name the local deployment directory (Deployment_OICP_<version>) and exits immediately, before any other check runs, if the pattern isn't found.
releasechecksum_urlOptional URL to the release package SHA-256 checksum. Upcoming feature - leave this field empty for now.
securityentra_admin_group.login / object_idExisting Entra ID admin group. Leave both empty to have the script create the group for you (it will prompt, unless you pass --auto-create-groups).
securitysql_admin_group.login / object_idExisting Entra ID SQL admin group. Same create-or-provide behavior as entra_admin_group.
shareddns_zone_namePublic DNS zone for Cloud Private custom domains (for example, mycompany.example.com). Required – it names the zone whether the zone is referenced or created (see create_dns_zone). With create_dns_zone set to false, the zone must already exist in Azure – the installer validates this and fails if not found.
sharedcreate_dns_zoneWhether the installer creates the DNS zone. Defaults to false, meaning the zone named in dns_zone_name must already exist. Set to true to have the installer create it.
shareddns_zone_resource_groupResource group of the existing DNS zone.
sharedcertificate_secret_nameName of the Azure Key Vault certificate. If certificate_file (below) is set, the installer imports it automatically with no prompt. If it's empty and the certificate isn't already in Key Vault, the script doesn't fail immediately – it presents an interactive menu to retry, import a certificate file on the spot, or quit (see the confirmations note under Step 4). Pre-uploading the certificate to Key Vault is only a hard requirement for --non-interactive runs, where that menu can't be answered and the phase fails instead.
sharedcertificate_fileOptional path to a certificate file (.pfx or .pem) on the machine running the installer. When set and the Key Vault certificate is missing, the installer imports it. The certificate password is read from the OMADA_CERT_PASSWORD environment variable, never from the config file.
infrastructureaks_system_node_sizeVM SKU for AKS system node pool (current automation default: Standard_D2s_v5).
infrastructureaks_app_node_sizeVM SKU for AKS application node pool (current automation default: Standard_D8s_v5).
infrastructureaks_linux_node_sizeVM SKU for the AKS Linux node pool (default: Standard_D4s_v5). This node pool is shared with Linux CAG workloads.
infrastructurecag_vm_sizeVM SKU for the Cloud Application Gateway VM (current automation default: Standard_D2s_v5).
infrastructureallowed_ip_addressesPublic IP allowlist applied to network rules on Key Vault, Storage, the SQL Server firewall, Service Bus, Event Hub, and NSGs. Defaults to []. The machine running the installer (or the pipeline agent) must be included in this list, or it will be locked out of these resources mid-install. The installer auto-adds its own detected public IP only when the list is empty; if you pre-populate it with other IPs (for example, office or VPN egress ranges), you must add the installer's IP yourself.
infrastructureenable_private_endpointsWhether to provision Azure Private Link endpoints for Key Vault, Storage, SQL Server, Event Hub, Service Bus, and App Services. Defaults to false.
infrastructureenable_public_accessControls public network access for App Services and SignalR only. Defaults to true. It does not affect the Key Vault, SQL Server, Event Hub, or Service Bus – those four always remain reachable over the public network by default, protected only by the allowed_ip_addresses firewall rules. Setting this to false does not, by itself, produce a fully private deployment.
infrastructureapplication_insights_sampling_percentageTelemetry sampling rate for Application Insights, from 0–100. Defaults to 100 (all telemetry captured).
secretsaks-extCertBase64, aks-extKeyBase64, aks-pfxCertificate, aks-pfxPassword, etc.Optional. Base64-encoded certificates and keys can be supplied here to pre-populate Key Vault; otherwise add them manually before the secrets_validate phase runs. The aks-containerRegistryDockerConfigJson secret is also required by validation but is generated automatically from the container registry credentials if not supplied.

Example deployment-config.json

The following example shows a fully filled-in deployment-config.json for a development environment.

{
"azure": {
"subscription_id": "00000000-0000-0000-0000-000000000000", // Your Azure subscription GUID
"tenant_id": "00000000-0000-0000-0000-000000000000", // Your Microsoft Entra ID tenant GUID
"location": "swedencentral" // Azure region for all resources
},
"deployment": {
"workspace_prefix": "ab0001", // 2 lowercase letters + 4 digits, e.g. ab0001
"project_name": "oicp", // Used to derive resource names; keep short and lowercase
"omada_license_string": "<provided-by-omada>",
"update_private_dns_records": true // Set to false to manage DNS records manually
},
"backend": {
"storage_account_name": "tfstateoicp", // Storage account for Terraform state; must be globally unique
"container_name": "tfstate", // Blob container name; "tfstate" is a safe default
"key": "terraform.tfstate" // State file name; default is "terraform.tfstate"
},
"release": {
"package_url": "<secure-url-provided-by-omada>",
"checksum_url": "<checksum-url-provided-by-omada>" // Optional; omit to skip checksum verification
},
"security": {
"entra_admin_group": {
"login": "omada-admins", // Display name of the Entra ID admin group
"object_id": "", // Leave empty to have the script create the group
"tenant_id": "" // Leave empty to use the tenant from azure.tenant_id
},
"sql_admin_group": {
"login": "omada-sql-admins", // Display name of the SQL admin group
"object_id": "", // Leave empty to have the script create the group
"tenant_id": "" // Leave empty to use the tenant from azure.tenant_id
}
},
"shared": {
"dns_zone_name": "omada.mycompany.com", // Required; the zone to reference or create
"create_dns_zone": false, // false: zone must already exist; true: installer creates it
"dns_zone_resource_group": "my-dns-rg", // Resource group containing the DNS zone
"certificate_secret_name": "omada-tls-cert", // Name of the certificate in Key Vault
"certificate_file": "" // Optional local .pfx/.pem to import if the certificate is missing
},
"infrastructure": {
"aks_system_node_size": "Standard_D2s_v5", // AKS system node pool VM SKU
"aks_app_node_size": "Standard_D8s_v5", // AKS application node pool VM SKU
"aks_linux_node_size": "Standard_D4s_v5", // AKS Linux node pool VM SKU (optional)
"cag_vm_size": "Standard_D2s_v5", // Cloud Application Gateway VM SKU
"enable_private_endpoints": false, // Set to true to enable Azure Private Link
"enable_public_access": true, // Controls public access for App Services/SignalR only – see table above
"allowed_ip_addresses": ["203.0.113.10"], // IPs allowed to reach AKS; auto-detected if empty
"logging_level": "minimal", // "minimal" (default) or "full"
"application_insights_sampling_percentage": 100 // Telemetry sampling rate (0–100)
},
"secrets": {
"aks-extCertBase64": "", // Base64-encoded external TLS certificate (.crt)
"aks-extKeyBase64": "", // Base64-encoded external TLS private key (.key)
"aks-pfxCertificate": "", // Base64-encoded PFX certificate
"aks-pfxPassword": "" // PFX certificate password
}
}

How to fill in this file:

You do not need to populate every field before running the script. As a starting point:

  • Fill in first: these specific fields are required, and the script will not start without them – azure.subscription_id, azure.tenant_id, azure.location, deployment.workspace_prefix, deployment.project_name, release.package_url, backend.storage_account_name, and shared.certificate_secret_name. Other fields in the same sections (for example, deployment.omada_license_string, backend.container_name/key, release.checksum_url) have defaults or are validated later, not at startup.

  • Confirm prerequisites exist (shared): the certificate doesn't strictly need to exist beforehand for an interactive run – if it's missing, the script offers to import one on the spot. Set certificate_file to skip that prompt and have it import automatically instead. For --non-interactive runs, the certificate must already be in Key Vault (or certificate_file must be set), since there's no prompt to answer if it's missing. Similarly, the DNS zone named in dns_zone_name must already exist in Azure, unless you set create_dns_zone to true to have the installer create it.

  • Choose your approach (security): leave object_id empty to let the script create your Entra ID admin groups automatically, or fill them in to use existing groups.

    note

    If entra_admin_group and sql_admin_group are left without an object_id, the script checks whether a group with the configured (or default) name already exists, and prompts to create it if not. When running with --non-interactive, you must either pre-populate both groups' object_id values or pass --auto-create-groups; otherwise the script will fail at this step rather than prompt.

  • Leave as-is unless you have specific requirements (infrastructure): the defaults work for most standard deployments.

  • Optional shortcut (secrets): supply base64-encoded certificates here to let the script push them to Key Vault automatically. If left empty, upload them to Key Vault manually before the script reaches the secrets_validate phase.

warning
  • Comments (prefixed //) are included for reference and must be removed from your actual file before use.

  • Workspace naming: The workspace_prefix must follow the format 2 lowercase letters + 4 digits exactly (for example, ab0001).

  • Key Vault secrets: Before running the full installer, you can validate Key Vault secrets independently using validate-secrets.sh --vault-name <name> (or --list to see required secrets without checking values). This flags any of the required secrets that are missing or still set to a placeholder before committing to a full multi-phase run. It does not validate the TLS certificate named in shared.certificate_secret_name – that certificate is checked separately by the full installer during the secrets_validate phase.

Infrastructure sizing

The default VM SKUs are configured in deployment-config.json via the aks_system_node_size, aks_app_node_size, aks_linux_node_size, and cag_vm_size parameters. For sizing profiles, SKU recommendations, and cost optimization guidance, see Azure infrastructure sizing in the Omada Identity Cloud Private overview.

Monitor CPU and memory usage in Azure portal after initial deployment to determine if scaling is needed.

Logging level

The logging_level field in the deployment-config.json file controls the verbosity of AKS cluster controller logs.

AKS cluster controller logs record the activity of Kubernetes controllers – the automated systems that manage cluster health and state. This includes pod restarts, node status checks, resource allocation decisions, and other routine cluster maintenance operations.

ValueDescription
minimalDefault. Logs essential cluster events only. Recommended for most deployments.
fullLogs all controller activity, including routine checks and updates. This mode generates high-volume logs and can rapidly fill the Log Analytics workspace.
note

Logging verbosity is separate from telemetry sampling, which is controlled by application_insights_sampling_percentage in the same section.

Step 3: Azure login

Authenticate with Azure CLI and verify you are on the correct subscription:

Tool: Bash shell

az login --tenant <your-tenant-id>
az account set --subscription <your-subscription-id>
az account show

Ensure your account has the Azure roles described in IdentityContributor (or Owner) and User Access Administrator (or Owner) at subscription scope.

Step 4: Run the installation script

From the installation directory, run:

Tool: Bash shell

./install.sh --config ./deployment-config.json
info

The ./deployment-config.json is the default value for --config, so this is equivalent to running ./install.sh with no arguments. It is provided here for full reference.

By default, the script logs progress to the following, relative to the installation directory (scripts/install) you're running it from (where <project> is your project_name and <workspace> is your workspace_prefix):

../../Deployment_OICP_<version>/run-<project>-<workspace>/logs/install-<timestamp>.log
info

Set the INSTALL_WORK_DIR environment variable to relocate the entire deployment directory elsewhere – useful if the installation directory's disk doesn't have enough room. For example:

INSTALL_WORK_DIR=/mnt/bigdisk/oicp-work ./install.sh --config ./deployment-config.json

When set, the deployment directory (and its logs) live at ${INSTALL_WORK_DIR}/Deployment_OICP_<version>/... instead of the default path above – adjust the tail command below accordingly.

Progress is shown live in the terminal in both interactive and non-interactive mode. To follow it from a separate terminal session instead – for example, if the installer is running in the background or over a connection you don't want to keep occupied – execute (from scripts/install – adjust the path if INSTALL_WORK_DIR is set):

Tool: Bash shell

tail -f ../../Deployment_OICP_<version>/run-<project>-<workspace>/logs/install-*.log
Interactive confirmations during installation

The script pauses for confirmation at several points during a fresh installation, typically:

  • At startup, after configuration is loaded (press Enter to continue).
  • Before creating Terraform backend resources (resource group, storage account, container), if they don't already exist.
  • Before publishing release artifacts to blob storage, and again before publishing container images to the registry.
  • Before each terraform apply (once for shared infrastructure, once for workspace-specific infrastructure).
  • If your detected OS version differs from Ubuntu 24.04.
  • If some of the requested VM sizes are not available in the selected Azure region (continuing may cause the deployment to fail).
  • During certificate validation (secrets_validate phase): if a required certificate is missing or invalid, the script presents a menu to retry, import a certificate file interactively, or quit. Have your certificate files (.pfx or .pem) accessible before running the script.

For the Yes/No prompts above, answer y to proceed. The certificate-validation menu is a numbered choice, not a Yes/No prompt – see its own bullet above for the options it presents.

Run the script in a regular interactive terminal session – not piped, backgrounded, or invoked from automation – so these prompts can be answered.

In --non-interactive mode, each prompt resolves to its default instead of pausing:

  • Prompts that default to Yes (the startup pause, Terraform backend resource creation, the two artifact-publish confirmations, and each terraform apply) are accepted automatically. A non-interactive run therefore creates backend resources and applies Terraform changes without pausing for review.
  • Prompts that default to No (the OS-mismatch confirmation and the VM-size availability warning) fail the run immediately.

The certificate validation menu does not block unattended runs – it automatically quits, failing the phase, if a certificate is missing.

Resuming an interrupted installation

If the installation is interrupted or a phase fails, resume from the last completed phase:

Tool: Bash shell

./install.sh --config ./deployment-config.json --resume

To clear all checkpoints and restart the entire installation:

Tool: Bash shell

./install.sh --config ./deployment-config.json --force
important
  • Each phase records its completion as a <phase_id>.done file containing the UTC timestamp of when it ran, stored in Deployment_OICP_<version>/run-<project>-<workspace>/. Deleting a phase's .done file will cause that phase to be re-executed the next time --resume is run.

  • --force clears all checkpoints but does not destroy Azure resources. To tear down infrastructure, use Azure portal or terraform destroy.

Automatic rollback on failure

If the installer fails after workspace-specific infrastructure has already been provisioned (the terraform_iac phase has completed) and --skip-terraform was not used, it prompts to roll back:

Prompt: Proceed with rollback (terraform destroy)? – default: No

  • Confirming runs terraform destroy against the workspace's infrastructure on a best-effort basis.
  • Declining (or a failure earlier than terraform_iac, or a run with --skip-terraform) leaves resources as they are; the log notes that resources may be in a partial state.
  • In --non-interactive mode, this prompt is never shown – it silently resolves to No, so resources are left in place and the run exits with its original error. Follow up with --resume to continue, or tear down manually through the Azure portal or terraform destroy.

There is currently no flag to disable this behavior when it would otherwise apply.

Common options

FlagDescription
-h, --helpPrint usage information and exit.
--resumeSkip completed phases and continue from the last failure.
--forceClear all checkpoints and re-run all phases.
--verbose, -vEnable debug output.
--dry-runSimulate Ansible execution without making changes (Ansible --check mode).
--skip-toolsSkip installing the toolchain. A verification step still runs regardless of this flag and requires az, terraform, kubectl, kubelogin, helm, skopeo, python3, jq, and ODBC Driver 18 to already be on PATH – the run fails immediately if any are missing. Use this flag only when the full toolchain is already installed and verified.
--skip-terraformSkip both Terraform phases, along with artifact publishing (blob and container registry), tfvars sync, and Key Vault secret validation — the entire Phase 7 block runs only when Terraform isn't skipped. Use only when a prior run already completed Phase 7 and you're re-running later phases.
--skip-ansibleSkip the Ansible configuration phase.
--skip-cagSkip the CAG VM configuration phase (runs by default otherwise).
--tags <tags>Restrict Ansible execution to specific tags (comma-separated). Useful for re-running a narrow slice of configuration, for example --tags dns_records.
--non-interactiveDisable interactive prompts; fail on missing input (CI/CD mode).
--auto-create-groupsCreate Entra ID groups automatically without prompting.
--entra-group-name <name>Override the default Entra admin group name (omada-admins).
--sql-group-name <name>Override the default SQL admin group name (omada-sql-admins).
--update-configWrite newly created Entra/SQL group IDs back into deployment-config.json.
--workspace <prefix>Override deployment.workspace_prefix from the command line.
--no-cacheForce re-download of the release package instead of reusing a cached copy.
Ansible warnings

During Ansible phases, you may see deprecation warnings related to ansible.module_utils._text imports (to_bytes, to_native, to_text). These warnings come from the Azure Ansible collection and do not affect task execution with the current pinned Ansible Core version. For details, see Known issue: Ansible module deprecation warnings.

Stage dependency overview

The installer runs the following phases in order, with each phase checkpointed on success. When using --resume, the script skips phases whose checkpoint already exists and continues from the first incomplete one – including resuming partway through the Ansible stage, since each Ansible sub-phase has its own checkpoint.

note

Two phases are an exception and always run on every invocation, checkpoint or not: config (to reload configuration values into the current shell) and terraform_backend (to re-validate, not recreate, the Terraform state backend). Neither performs destructive or duplicate work when re-run.

OrderStagePurpose
1preflightOS, disk, network checks.
2configLoad and validate deployment-config.json.
3toolsInstall toolchain (Terraform, Ansible, kubectl, etc.).
4azureAzure auth, RBAC and quota checks, Entra/SQL group provisioning.
5terraform_backendCreate or validate Terraform state storage.
6releaseDownload and extract Cloud Private release package.
7terraform_iac_sharedProvision shared global infrastructure.
8artifacts_publish_blobPublish release artifacts to blob storage.
9artifacts_publish_acrPublish container images to ACR.
10tfvars_syncSync release-derived values into Terraform variables.
11secrets_validateValidate Key Vault certificates and secrets.
12terraform_iacProvision workspace-specific infrastructure.
13ansible_db_preaksTier 1 – pre-AKS database setup.
14ansible_deploy_aksPhase 1 – deploy AKS cluster, ES pod, Timer pod, and DNS records.
15ansible_cagCAG VM pre-configuration (skipped with --skip-cag).
16ansible_configure_esTier 2+3 – ES configuration (changeset import, provisioning, connectivity).
17ansible_deploy_aks_phase2Phase 2 – deploy RoPE and CagOps pods.
18health_checkAutomated post-deployment health check. Detailed documentation: Post-deployment health check.

Completed phases are marked with checkpoint files under Deployment_OICP_<version>/run-<project>-<workspace>/.

note

Review the installation log for the health_check phase result and address any reported issues before handing over the environment. For the full validation checklist, see Deployment validation checklist in the Deployment guide.

If the health check reports failures or warnings and you need to troubleshoot further, see Collecting debug logs to gather diagnostic data for analysis or to send to Omada Support.