The convergence of Red Hat OpenShift and Pulumi represents a fundamental shift in how enterprise-grade container orchestration is provisioned and maintained. By synthesizing the robust, opinionated container platform of OpenShift with the expressive, multi-language Infrastructure as Code (IaC) capabilities of Pulumi, organizations can eliminate the operational bottlenecks traditionally associated with cluster lifecycle management. The traditional friction point in cluster provisioning often manifests as a "manual approval" stage within a cloud console—a gap that disrupts the continuous delivery pipeline and introduces human error. OpenShift Pulumi closes this gap by treating access, policy, and deployment as version-controlled code, thereby transforming the deployment process into a repeatable, reason-aboutable engineering workflow.
OpenShift provides a consistent Kubernetes experience at scale, utilizing Operators for lifecycle management, rigorous Role-Based Access Control (RBAC), and strong multi-tenant isolation. When Pulumi is introduced into this ecosystem, it allows developers to define the entire environment—including the cluster itself, application workloads, and complex Identity and Access Management (IAM) boundaries—within a single, unified workflow. The primary impact of this integration is the establishment of an immutable trust model where every namespace, secret, and cluster configuration adheres to corporate policy from the very first line of code. This eliminates "configuration drift" and ensures that the production environment is an exact replica of the tested staging environment.
The technical integration is centered on identity and declarative state. Pulumi leverages existing cloud credentials or OpenID Connect (OIDC) tokens to establish a secure session with the OpenShift API. Once authentication is successful, Pulumi acts as the driver for the OpenShift API, applying declarative state changes. This means that instead of executing a series of imperative commands to modify a cluster, the user defines the desired end-state, and Pulumi calculates the delta between the current state and the target state, executing only the necessary changes. This process integrates seamlessly into CI/CD pipelines, creating a GitOps model where infrastructure is versioned in Git, and updates are triggered by pull requests, effectively eliminating the risk of "surprise merges" and undocumented manual changes.
Architectural Components of Azure Red Hat OpenShift (ARO)
When utilizing the azure-native provider in Pulumi, the OpenShiftCluster resource serves as the primary entity representing an Azure Red Hat OpenShift cluster. This resource is highly complex, requiring detailed configurations across networking, compute, and identity profiles to ensure the cluster is production-ready.
The Cluster Profile and API Server
The ClusterProfile defines the foundational identity and location of the cluster. This include the domain name (e.g., cluster.location.aroapp.io) and the resource group ID where the cluster resides. A critical security component within the ClusterProfile is the PullSecret, which provides the necessary authentication to the Red Hat registries (specifically registry.connect.redhat.com and registry.redhat.io) to pull the required container images for the control plane and worker nodes.
The APIServerProfile controls the accessibility of the Kubernetes API. The Visibility attribute is paramount here, as it determines whether the API server is accessible via a public endpoint (VisibilityPublic) or restricted to internal network traffic, which is a common requirement for high-security government or financial environments.
Master and Worker Node Profiles
The compute capacity of an ARO cluster is divided into two distinct profiles: the MasterProfile and the WorkerProfileArray.
The MasterProfile governs the control plane nodes. Key configurations include:
- VmSize: Determines the CPU and memory capacity of the master nodes (e.g., Standard_D8s_v3).
- SubnetId: The specific Azure Virtual Network subnet where the master nodes are deployed.
- EncryptionAtHost: Controls whether data is encrypted at the host level (EncryptionAtHostEnabled).
- DiskEncryptionSetId: Provides a reference to the encryption set used for the master disks.
The WorkerProfileArray allows for the definition of one or more sets of worker nodes, facilitating the segregation of workloads based on resource needs. Each worker profile requires:
- Count: The number of worker nodes to deploy (e.g., 3).
- DiskSizeGB: The storage capacity for the worker node disks (e.g., 128).
- VmSize: The virtual machine size (e.g., Standard_D2s_v3).
- SubnetId: The dedicated subnet for worker nodes, ensuring network isolation from the master nodes.
- Name: A unique identifier for the worker group (e.g., worker).
Network Configuration and Ingress Logic
Networking is perhaps the most complex aspect of the azure-native OpenShift deployment. Pulumi allows for granular control over how traffic enters and leaves the cluster, which is essential for maintaining a secure perimeter.
Network Profile Specifications
The NetworkProfile manages the internal IP addressing and egress traffic of the cluster. It comprises several critical fields:
- PodCidr: The Classless Inter-Domain Routing (CIDR) block used for Pods (e.g., 10.128.0.0/14). This must be carefully planned to avoid overlaps with existing corporate networks.
- ServiceCidr: The CIDR block allocated for Kubernetes services (e.g., 172.30.0.0/16).
- OutboundType: Defines how egress traffic is handled, which impacts how the cluster communicates with external APIs or databases.
- PreconfiguredNSG: Determines if a preconfigured Network Security Group (NSG) is used or if it should be disabled (PreconfiguredNSGDisabled).
Load Balancer and Ingress
The LoadBalancerProfile within the NetworkProfile handles the distribution of incoming traffic. A key setting here is the ManagedOutboundIps, which can specify the number of outbound IP addresses to ensure the cluster has sufficient egress capacity.
Complementing the load balancer is the IngressProfileArray. This allows administrators to define one or more ingress points. Each profile requires a Name (e.g., default) and a Visibility setting (e.g., VisibilityPublic), which determines if the application endpoints are exposed to the internet or restricted to a private network.
Authentication and Identity Management
Connecting Pulumi to OpenShift requires a robust identity handshake. This is not a one-time setup but a continuous authentication flow that ensures only authorized entities can modify the infrastructure.
Authentication Methods
Pulumi supports two primary methods for connecting to an OpenShift cluster:
- Cloud Credentials: Pulumi utilizes the pre-configured credentials of the cloud provider (Azure) to authenticate via the azure-native provider.
- OIDC Identity Providers: For more granular control and alignment with corporate identity standards, Pulumi can authenticate using OpenID Connect (OIDC) tokens.
Once authentication is established, the Pulumi stack configuration is pointed toward the specific cluster endpoint. When the pulumi up command is executed, Pulumi opens a secure session and applies the resource changes. This operational flow is functionally similar to using kubectl, but it is superior because it is governed by policy-as-code and tracked in a state file.
Identity Security Best Practices
To maintain a high security posture, the following strategies should be implemented:
- Least Privilege Mapping: OpenShift service accounts should be mapped to specific Pulumi stacks. This ensures that a stack responsible for deploying a minor application cannot accidentally delete the entire cluster.
- Automated Rotation: Tokens and certificates used for authentication should be rotated automatically using a dedicated secrets manager.
- State Validation: By exporting stack states and validating them within a CI pipeline, teams can track policy drift and automatically remediate unauthorized changes.
- State Diff Debugging: When a deployment fails, the Pulumi state diff should be the primary debugging tool, as it provides a clear view of exactly what changed in the infrastructure, which is significantly more efficient than parsing logs across multiple pods.
Implementation Details and API Versioning
The azure-native provider is subject to frequent updates as Azure Red Hat OpenShift evolves. Understanding API versioning is critical for ensuring that infrastructure remains stable and reproducible.
API Version History
The OpenShiftCluster resource utilizes different versions of the Azure REST API depending on the provider version being used:
- Current Version: The most recent implementation uses Azure REST API version 2023-11-22.
- Legacy Version: In version 2.x of the Azure Native provider, API version 2022-09-04 was utilized.
For organizations that require a specific API version to maintain compatibility with older templates or specific feature sets, Pulumi allows the generation of a local SDK package. This is achieved using the following CLI command:
pulumi package add azure-native redhatopenshift [ApiVersion]
The available API versions include:
- 2022-09-04
- 2023-04-01
- 2023-07-01-preview
- 2023-09-04
- 2024-08-12-preview
- 2025-07-25
Programmatic Implementation in Go
The following table summarizes the key Go-based configuration arguments used when initializing a new OpenShift cluster via the redhatopenshift.NewOpenShiftCluster function.
| Argument | Example Value | Purpose |
|---|---|---|
ApiserverProfile.Visibility |
redhatopenshift.VisibilityPublic |
Sets the API server access level |
ClusterProfile.Domain |
cluster.location.aroapp.io |
Sets the base domain for the cluster |
ClusterProfile.FipsValidatedModules |
redhatopenshift.FipsValidatedModulesEnabled |
Enables FIPS compliance for security |
MasterProfile.VmSize |
Standard_D8s_v3 |
Defines the control plane node size |
NetworkProfile.PodCidr |
10.128.0.0/14 |
Defines the Pod IP range |
WorkerProfiles.Count |
3 |
Defines number of worker nodes |
Code Implementation Example
For a technical implementation, the following Go code demonstrates the instantiation of a cluster. Note the strict requirement for a ServicePrincipalProfile to provide the ClientId and ClientSecret necessary for Azure to provision the Red Hat OpenShift resources on the user's behalf.
```go
package main
import (
redhatopenshift "github.com/pulumi/pulumi-azure-native-sdk/redhatopenshift/v3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
, err := redhatopenshift.NewOpenShiftCluster(ctx, "openShiftCluster", &redhatopenshift.OpenShiftClusterArgs{
ApiserverProfile: &redhatopenshift.APIServerProfileArgs{
Visibility: pulumi.String(redhatopenshift.VisibilityPublic),
},
ClusterProfile: &redhatopenshift.ClusterProfileArgs{
Domain: pulumi.String("cluster.location.aroapp.io"),
FipsValidatedModules: pulumi.String(redhatopenshift.FipsValidatedModulesEnabled),
PullSecret: pulumi.String({"auths":{"registry.connect.redhat.com":{"auth":""},"registry.redhat.io":{"auth":""}}}),
ResourceGroupId: pulumi.String("/subscriptions/subscriptionId/resourceGroups/clusterResourceGroup"),
},
IngressProfiles: redhatopenshift.IngressProfileArray{
&redhatopenshift.IngressProfileArgs{
Name: pulumi.String("default"),
Visibility: pulumi.String(redhatopenshift.VisibilityPublic),
},
},
Location: pulumi.String("location"),
MasterProfile: &redhatopenshift.MasterProfileArgs{
EncryptionAtHost: pulumi.String(redhatopenshift.EncryptionAtHostEnabled),
SubnetId: pulumi.String("/subscriptions/subscriptionId/resourceGroups/vnetResourceGroup/providers/Microsoft.Network/virtualNetworks/vnet/subnets/master"),
VmSize: pulumi.String("StandardD8sv3"),
},
NetworkProfile: &redhatopenshift.NetworkProfileArgs{
LoadBalancerProfile: &redhatopenshift.LoadBalancerProfileArgs{
ManagedOutboundIps: &redhatopenshift.ManagedOutboundIPsArgs{
Count: pulumi.Int(1),
},
},
PodCidr: pulumi.String("10.128.0.0/14"),
PreconfiguredNSG: pulumi.String(redhatopenshift.PreconfiguredNSGDisabled),
ServiceCidr: pulumi.String("172.30.0.0/16"),
},
ResourceGroupName: pulumi.String("resourceGroup"),
ResourceName: pulumi.String("resourceName"),
ServicePrincipalProfile: &redhatopenshift.ServicePrincipalProfileArgs{
ClientId: pulumi.String("clientId"),
ClientSecret: pulumi.String("clientSecret"),
},
Tags: pulumi.StringMap{
"key": pulumi.String("value"),
},
WorkerProfiles: redhatopenshift.WorkerProfileArray{
&redhatopenshift.WorkerProfileArgs{
Count: pulumi.Int(3),
DiskSizeGB: pulumi.Int(128),
Name: pulumi.String("worker"),
SubnetId: pulumi.String("/subscriptions/subscriptionId/resourceGroups/vnetResourceGroup/providers/Microsoft.Network/virtualNetworks/vnet/subnets/worker"),
VmSize: pulumi.String("StandardD2s_v3"),
},
},
})
if err != nil {
return err
}
return nil
})
}
```
For those utilizing HCL-like syntax through the Pulumi provider, the resource definition is structured as follows:
```hcl
pulumi {
required_providers {
azure-native = {
source = "pulumi/azure-native"
}
}
}
resource "azure-nativeredhatopenshiftopenshiftcluster" "openShiftCluster" {
# Configuration details would follow here
}
```
Comprehensive Analysis of the GitOps Transition
The transition from manual console-based configuration to a Pulumi-driven OpenShift workflow is not merely a change in tooling, but a fundamental change in operational philosophy. By encoding the infrastructure, the organization moves from a "snowflake" model—where each cluster is uniquely tweaked by an administrator—to a "cattle" model, where clusters are ephemeral, reproducible, and disposable.
The integration of CI/CD pipelines ensures that every change to the OpenShift environment undergoes the same rigor as application code. A developer proposing a change to the WorkerProfile to increase the VmSize from Standard_D2s_v3 to a larger instance does not simply apply the change; they submit a pull request. This request is then subjected to automated linting, policy checks (using tools like Pulumi CrossGuard), and peer review. Once merged, the pipeline executes pulumi up, and the Azure Native provider communicates with the Azure REST API to resize the nodes without requiring a manual session in the Azure Portal.
Furthermore, the use of FipsValidatedModulesEnabled within the ClusterProfile demonstrates how compliance can be baked into the infrastructure. In highly regulated industries, proving that a cluster is FIPS-compliant typically requires manual audits of VM images and OS configurations. With Pulumi, the compliance is declared in the code. The fact that FipsValidatedModules is set to enabled in the version-controlled repository serves as a living audit trail, ensuring that every cluster deployed across the enterprise meets the same security baseline.
The synergy between OpenShift's Operator framework and Pulumi's declarative state creates a powerful feedback loop. While Pulumi manages the "outer loop" (the cluster, the network, and the VM sizes), OpenShift Operators manage the "inner loop" (the application lifecycle, the database patching, and the monitoring stacks). This separation of concerns allows the infrastructure team to focus on the stability and scalability of the platform, while the development teams focus on the delivery of the application, both operating within a framework of absolute transparency and repeatability.