Create AWS Mainframe Modernization Environments

The aws:m2/environment:Environment resource, part of the Pulumi AWS provider, provisions the runtime infrastructure for AWS Mainframe Modernization applications: compute instances, networking, and optional storage. This guide focuses on three capabilities: engine type and instance sizing, high availability configuration, and EFS and FSX storage attachment.

Mainframe Modernization environments run in VPC subnets with security groups and may mount EFS or FSX filesystems. The examples are intentionally small. Combine them with your own VPC infrastructure and storage resources.

Create a runtime environment for mainframe applications

Mainframe Modernization environments provide the runtime for migrated COBOL or PL/I applications. Start by defining the engine type, instance size, and network placement.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const test = new aws.m2.Environment("test", {
    name: "test-env",
    engineType: "bluage",
    instanceType: "M2.m5.large",
    securityGroups: ["sg-01234567890abcdef"],
    subnetIds: [
        "subnet-01234567890abcdef",
        "subnet-01234567890abcdea",
    ],
});
import pulumi
import pulumi_aws as aws

test = aws.m2.Environment("test",
    name="test-env",
    engine_type="bluage",
    instance_type="M2.m5.large",
    security_groups=["sg-01234567890abcdef"],
    subnet_ids=[
        "subnet-01234567890abcdef",
        "subnet-01234567890abcdea",
    ])
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/m2"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := m2.NewEnvironment(ctx, "test", &m2.EnvironmentArgs{
			Name:         pulumi.String("test-env"),
			EngineType:   pulumi.String("bluage"),
			InstanceType: pulumi.String("M2.m5.large"),
			SecurityGroups: []string{
				"sg-01234567890abcdef",
			},
			SubnetIds: pulumi.StringArray{
				pulumi.String("subnet-01234567890abcdef"),
				pulumi.String("subnet-01234567890abcdea"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var test = new Aws.M2.Environment("test", new()
    {
        Name = "test-env",
        EngineType = "bluage",
        InstanceType = "M2.m5.large",
        SecurityGroups = new[]
        {
            "sg-01234567890abcdef",
        },
        SubnetIds = new[]
        {
            "subnet-01234567890abcdef",
            "subnet-01234567890abcdea",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.m2.Environment;
import com.pulumi.aws.m2.EnvironmentArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var test = new Environment("test", EnvironmentArgs.builder()
            .name("test-env")
            .engineType("bluage")
            .instanceType("M2.m5.large")
            .securityGroups(List.of("sg-01234567890abcdef"))
            .subnetIds(            
                "subnet-01234567890abcdef",
                "subnet-01234567890abcdea")
            .build());

    }
}
resources:
  test:
    type: aws:m2:Environment
    properties:
      name: test-env
      engineType: bluage
      instanceType: M2.m5.large
      securityGroups:
        - sg-01234567890abcdef
      subnetIds:
        - subnet-01234567890abcdef
        - subnet-01234567890abcdea

The engineType property specifies which modernization engine to use: “bluage” for COBOL applications or “microfocus” for PL/I workloads. The instanceType determines compute capacity. The environment runs in your specified subnets with attached security groups, which control network access to and from the instances.

Enable high availability with multiple instances

Production workloads require redundancy to handle instance failures without downtime.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const test = new aws.m2.Environment("test", {
    name: "test-env",
    engineType: "bluage",
    instanceType: "M2.m5.large",
    securityGroups: ["sg-01234567890abcdef"],
    subnetIds: [
        "subnet-01234567890abcdef",
        "subnet-01234567890abcdea",
    ],
    highAvailabilityConfig: {
        desiredCapacity: 2,
    },
});
import pulumi
import pulumi_aws as aws

test = aws.m2.Environment("test",
    name="test-env",
    engine_type="bluage",
    instance_type="M2.m5.large",
    security_groups=["sg-01234567890abcdef"],
    subnet_ids=[
        "subnet-01234567890abcdef",
        "subnet-01234567890abcdea",
    ],
    high_availability_config={
        "desired_capacity": 2,
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/m2"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := m2.NewEnvironment(ctx, "test", &m2.EnvironmentArgs{
			Name:         pulumi.String("test-env"),
			EngineType:   pulumi.String("bluage"),
			InstanceType: pulumi.String("M2.m5.large"),
			SecurityGroups: []string{
				"sg-01234567890abcdef",
			},
			SubnetIds: pulumi.StringArray{
				pulumi.String("subnet-01234567890abcdef"),
				pulumi.String("subnet-01234567890abcdea"),
			},
			HighAvailabilityConfig: &m2.EnvironmentHighAvailabilityConfigArgs{
				DesiredCapacity: pulumi.Int(2),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var test = new Aws.M2.Environment("test", new()
    {
        Name = "test-env",
        EngineType = "bluage",
        InstanceType = "M2.m5.large",
        SecurityGroups = new[]
        {
            "sg-01234567890abcdef",
        },
        SubnetIds = new[]
        {
            "subnet-01234567890abcdef",
            "subnet-01234567890abcdea",
        },
        HighAvailabilityConfig = new Aws.M2.Inputs.EnvironmentHighAvailabilityConfigArgs
        {
            DesiredCapacity = 2,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.m2.Environment;
import com.pulumi.aws.m2.EnvironmentArgs;
import com.pulumi.aws.m2.inputs.EnvironmentHighAvailabilityConfigArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var test = new Environment("test", EnvironmentArgs.builder()
            .name("test-env")
            .engineType("bluage")
            .instanceType("M2.m5.large")
            .securityGroups(List.of("sg-01234567890abcdef"))
            .subnetIds(            
                "subnet-01234567890abcdef",
                "subnet-01234567890abcdea")
            .highAvailabilityConfig(EnvironmentHighAvailabilityConfigArgs.builder()
                .desiredCapacity(2)
                .build())
            .build());

    }
}
resources:
  test:
    type: aws:m2:Environment
    properties:
      name: test-env
      engineType: bluage
      instanceType: M2.m5.large
      securityGroups:
        - sg-01234567890abcdef
      subnetIds:
        - subnet-01234567890abcdef
        - subnet-01234567890abcdea
      highAvailabilityConfig:
        desiredCapacity: 2

The highAvailabilityConfig property spreads the environment across multiple instances. The desiredCapacity sets how many instances to maintain. For true high availability, provide subnets in different availability zones so AWS can distribute instances across failure domains.

Attach EFS for shared persistent storage

Applications that need shared file access across instances or persistent data beyond instance lifecycles can mount an EFS filesystem.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const test = new aws.m2.Environment("test", {
    name: "test-env",
    engineType: "bluage",
    instanceType: "M2.m5.large",
    securityGroups: ["sg-01234567890abcdef"],
    subnetIds: [
        "subnet-01234567890abcdef",
        "subnet-01234567890abcdea",
    ],
    storageConfiguration: {
        efs: {
            fileSystemId: "fs-01234567890abcdef",
            mountPoint: "/m2/mount/example",
        },
    },
});
import pulumi
import pulumi_aws as aws

test = aws.m2.Environment("test",
    name="test-env",
    engine_type="bluage",
    instance_type="M2.m5.large",
    security_groups=["sg-01234567890abcdef"],
    subnet_ids=[
        "subnet-01234567890abcdef",
        "subnet-01234567890abcdea",
    ],
    storage_configuration={
        "efs": {
            "file_system_id": "fs-01234567890abcdef",
            "mount_point": "/m2/mount/example",
        },
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/m2"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := m2.NewEnvironment(ctx, "test", &m2.EnvironmentArgs{
			Name:         pulumi.String("test-env"),
			EngineType:   pulumi.String("bluage"),
			InstanceType: pulumi.String("M2.m5.large"),
			SecurityGroups: []string{
				"sg-01234567890abcdef",
			},
			SubnetIds: pulumi.StringArray{
				pulumi.String("subnet-01234567890abcdef"),
				pulumi.String("subnet-01234567890abcdea"),
			},
			StorageConfiguration: &m2.EnvironmentStorageConfigurationArgs{
				Efs: &m2.EnvironmentStorageConfigurationEfsArgs{
					FileSystemId: pulumi.String("fs-01234567890abcdef"),
					MountPoint:   pulumi.String("/m2/mount/example"),
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var test = new Aws.M2.Environment("test", new()
    {
        Name = "test-env",
        EngineType = "bluage",
        InstanceType = "M2.m5.large",
        SecurityGroups = new[]
        {
            "sg-01234567890abcdef",
        },
        SubnetIds = new[]
        {
            "subnet-01234567890abcdef",
            "subnet-01234567890abcdea",
        },
        StorageConfiguration = new Aws.M2.Inputs.EnvironmentStorageConfigurationArgs
        {
            Efs = new Aws.M2.Inputs.EnvironmentStorageConfigurationEfsArgs
            {
                FileSystemId = "fs-01234567890abcdef",
                MountPoint = "/m2/mount/example",
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.m2.Environment;
import com.pulumi.aws.m2.EnvironmentArgs;
import com.pulumi.aws.m2.inputs.EnvironmentStorageConfigurationArgs;
import com.pulumi.aws.m2.inputs.EnvironmentStorageConfigurationEfsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var test = new Environment("test", EnvironmentArgs.builder()
            .name("test-env")
            .engineType("bluage")
            .instanceType("M2.m5.large")
            .securityGroups(List.of("sg-01234567890abcdef"))
            .subnetIds(            
                "subnet-01234567890abcdef",
                "subnet-01234567890abcdea")
            .storageConfiguration(EnvironmentStorageConfigurationArgs.builder()
                .efs(EnvironmentStorageConfigurationEfsArgs.builder()
                    .fileSystemId("fs-01234567890abcdef")
                    .mountPoint("/m2/mount/example")
                    .build())
                .build())
            .build());

    }
}
resources:
  test:
    type: aws:m2:Environment
    properties:
      name: test-env
      engineType: bluage
      instanceType: M2.m5.large
      securityGroups:
        - sg-01234567890abcdef
      subnetIds:
        - subnet-01234567890abcdef
        - subnet-01234567890abcdea
      storageConfiguration:
        efs:
          fileSystemId: fs-01234567890abcdef
          mountPoint: /m2/mount/example

The storageConfiguration property’s efs block connects an existing EFS filesystem to the environment. The fileSystemId references your filesystem, and mountPoint specifies where it appears in the instance filesystem. All instances in the environment share the same mounted storage.

Attach FSX for Windows-compatible storage

Some mainframe applications require Windows-compatible file systems or need FSX’s performance characteristics.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const test = new aws.m2.Environment("test", {
    name: "test-env",
    engineType: "bluage",
    instanceType: "M2.m5.large",
    securityGroups: ["sg-01234567890abcdef"],
    subnetIds: [
        "subnet-01234567890abcdef",
        "subnet-01234567890abcdea",
    ],
    storageConfiguration: {
        fsx: {
            fileSystemId: "fs-01234567890abcdef",
            mountPoint: "/m2/mount/example",
        },
    },
});
import pulumi
import pulumi_aws as aws

test = aws.m2.Environment("test",
    name="test-env",
    engine_type="bluage",
    instance_type="M2.m5.large",
    security_groups=["sg-01234567890abcdef"],
    subnet_ids=[
        "subnet-01234567890abcdef",
        "subnet-01234567890abcdea",
    ],
    storage_configuration={
        "fsx": {
            "file_system_id": "fs-01234567890abcdef",
            "mount_point": "/m2/mount/example",
        },
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/m2"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := m2.NewEnvironment(ctx, "test", &m2.EnvironmentArgs{
			Name:         pulumi.String("test-env"),
			EngineType:   pulumi.String("bluage"),
			InstanceType: pulumi.String("M2.m5.large"),
			SecurityGroups: []string{
				"sg-01234567890abcdef",
			},
			SubnetIds: pulumi.StringArray{
				pulumi.String("subnet-01234567890abcdef"),
				pulumi.String("subnet-01234567890abcdea"),
			},
			StorageConfiguration: &m2.EnvironmentStorageConfigurationArgs{
				Fsx: &m2.EnvironmentStorageConfigurationFsxArgs{
					FileSystemId: pulumi.String("fs-01234567890abcdef"),
					MountPoint:   pulumi.String("/m2/mount/example"),
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var test = new Aws.M2.Environment("test", new()
    {
        Name = "test-env",
        EngineType = "bluage",
        InstanceType = "M2.m5.large",
        SecurityGroups = new[]
        {
            "sg-01234567890abcdef",
        },
        SubnetIds = new[]
        {
            "subnet-01234567890abcdef",
            "subnet-01234567890abcdea",
        },
        StorageConfiguration = new Aws.M2.Inputs.EnvironmentStorageConfigurationArgs
        {
            Fsx = new Aws.M2.Inputs.EnvironmentStorageConfigurationFsxArgs
            {
                FileSystemId = "fs-01234567890abcdef",
                MountPoint = "/m2/mount/example",
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.m2.Environment;
import com.pulumi.aws.m2.EnvironmentArgs;
import com.pulumi.aws.m2.inputs.EnvironmentStorageConfigurationArgs;
import com.pulumi.aws.m2.inputs.EnvironmentStorageConfigurationFsxArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var test = new Environment("test", EnvironmentArgs.builder()
            .name("test-env")
            .engineType("bluage")
            .instanceType("M2.m5.large")
            .securityGroups(List.of("sg-01234567890abcdef"))
            .subnetIds(            
                "subnet-01234567890abcdef",
                "subnet-01234567890abcdea")
            .storageConfiguration(EnvironmentStorageConfigurationArgs.builder()
                .fsx(EnvironmentStorageConfigurationFsxArgs.builder()
                    .fileSystemId("fs-01234567890abcdef")
                    .mountPoint("/m2/mount/example")
                    .build())
                .build())
            .build());

    }
}
resources:
  test:
    type: aws:m2:Environment
    properties:
      name: test-env
      engineType: bluage
      instanceType: M2.m5.large
      securityGroups:
        - sg-01234567890abcdef
      subnetIds:
        - subnet-01234567890abcdef
        - subnet-01234567890abcdea
      storageConfiguration:
        fsx:
          fileSystemId: fs-01234567890abcdef
          mountPoint: /m2/mount/example

The fsx block works like the efs block but connects an FSX filesystem instead. FSX provides Windows-compatible storage and different performance profiles than EFS. Only one storage type (EFS or FSX) can be configured per environment.

Beyond these examples

These snippets focus on specific environment-level features: engine and instance type selection, high availability configuration, and EFS and FSX storage attachment. They’re intentionally minimal rather than full mainframe migration solutions.

The examples reference pre-existing infrastructure such as VPC subnets and security groups, and EFS or FSX filesystems for storage examples. They focus on configuring the environment rather than provisioning the surrounding infrastructure.

To keep things focused, common environment patterns are omitted, including:

  • Public accessibility controls (publiclyAccessible)
  • KMS encryption (kmsKeyId)
  • Maintenance window scheduling (preferredMaintenanceWindow)
  • Force update behavior (forceUpdate)

These omissions are intentional: the goal is to illustrate how each environment feature is wired, not provide drop-in mainframe modules. See the Mainframe Modernization Environment resource reference for all available configuration options.

Let's create AWS Mainframe Modernization Environments

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Configuration & Setup
What are the required fields to create an environment?
You must provide name, engineType, engineVersion, instanceType, securityGroupIds, subnetIds, publiclyAccessible, and preferredMaintenanceWindow. The name must be unique within your AWS account.
What engine types can I use?
The engineType must be either microfocus or bluage.
What format does the maintenance window require?
Use the format ddd:hh24:mi-ddd:hh24:mi (e.g., sun:05:00-sun:09:00) and ensure the duration is less than 24 hours. If not provided, a random value will be used.
Storage & Persistence
What storage options are available?
You can configure either EFS or FSX storage using storageConfiguration. For EFS, provide efs.fileSystemId and efs.mountPoint. For FSX, provide fsx.fileSystemId and fsx.mountPoint.
Can I encrypt my environment with a KMS key?
Yes, provide the kmsKeyId parameter with the ARN of your KMS key.
High Availability & Maintenance
How do I set up high availability?
Configure highAvailabilityConfig with desiredCapacity set to 2 or higher to enable high availability.
Can I update my environment while applications are running?
Yes, set forceUpdate to true to force updates even when applications are running.
Networking & Access
How do I make my environment publicly accessible?
Set publiclyAccessible to true to allow applications deployed to this environment to be publicly accessible.
What networking configuration is required?
You must provide securityGroupIds (list of security group IDs) and subnetIds (list of subnet IDs) to deploy the environment into your VPC.
How do I get the load balancer ARN for my environment?
The loadBalancerArn is a computed output property available after the environment is created.

Using a different cloud?

Explore compute guides for other cloud providers: