Dieser Inhalt ist in der von Ihnen ausgewählten Sprache nicht verfügbar.

Chapter 4. User-provisioned infrastructure


4.1. Preparing to install a cluster on AWS

To install an OpenShift Container Platform cluster on Amazon Web Services (AWS), you must complete several tasks in order to prepare your environment.

You prepare to install an OpenShift Container Platform cluster on AWS by completing the following steps:

  • Verifying internet connectivity for your cluster.
  • Configuring an AWS account. For more information, see "Configuring an AWS account".
  • Downloading the installation program.

    Note

    If you are installing in a disconnected environment, you extract the installation program from the mirrored content. For more information, see "Mirroring images for a disconnected installation".

  • Installing the OpenShift CLI (oc).

    Note

    If you are installing in a disconnected environment, install oc to the mirror host.

  • Generating an SSH key pair. You can use this key pair to authenticate into the OpenShift Container Platform cluster’s nodes after it is deployed.
  • Preparing the user-provisioned infrastructure. For more information, see "Installation requirements for user-provisioned infrastructure on AWS".
  • If the cloud identity and access management (IAM) APIs are not accessible in your environment, or if you do not want to store an administrator-level credential secret in the kube-system namespace, manually creating long-term credentials for AWS or configuring an AWS cluster to use short-term credentials with (AWS STS). For more information, see "Manually creating long-term credentials" and "Configuring an AWS cluster to use short-term credentials".

4.1.1. Internet access for OpenShift Container Platform

In OpenShift Container Platform 4.21, you require access to the internet to install your cluster.

You must have internet access to perform the following actions:

  • Access Red Hat Hybrid Cloud Console to download the installation program and perform subscription management. If the cluster has internet access and you do not disable Telemetry, that service automatically entitles your cluster.
  • Access Quay.io to obtain the packages that are required to install your cluster.
  • Obtain the packages that are required to perform cluster updates.
Important

If your cluster cannot have direct internet access, you can perform a restricted network installation on some types of infrastructure that you provision. During that process, you download the required content and use it to populate a mirror registry with the installation packages. With some installation types, the environment that you install your cluster in will not require internet access. Before you update the cluster, you update the content of the mirror registry.

4.1.2. Obtaining the installation program

Before you install OpenShift Container Platform, download the installation file on the host you are using for installation, so that installation assets exist for deployment in your environment.

Prerequisites

  • You have a computer that runs Linux or macOS, with 500 MB of local disk space.

Procedure

  1. Go to the Cluster Type page on the Red Hat Hybrid Cloud Console. If you have a Red Hat account, log in with your credentials. If you do not, create an account.

    Tip
  2. Select your infrastructure provider from the Run it yourself section of the page.
  3. Select your host operating system and architecture from the dropdown menus under OpenShift Installer and click Download Installer.
  4. Place the downloaded file in the directory where you want to store the installation configuration files.

    Important
    • The installation program creates several files on the computer that you use to install your cluster. You must keep the installation program and the files that the installation program creates after you finish installing the cluster. Both of the files are required to delete the cluster.
    • Deleting the files created by the installation program does not remove your cluster, even if the cluster failed during installation. To remove your cluster, complete the OpenShift Container Platform uninstallation procedures for your specific cloud provider.
  5. Extract the installation program. For example, on a computer that uses a Linux operating system, run the following command:

    $ tar -xvf openshift-install-linux.tar.gz
  6. Download your installation pull secret from Red Hat OpenShift Cluster Manager. This pull secret allows you to authenticate with the services that are provided by the included authorities, including Quay.io, which serves the container images for OpenShift Container Platform components.

    Tip

    Alternatively, you can retrieve the installation program from the Red Hat Customer Portal, where you can specify a version of the installation program to download. However, you must have an active subscription to access this page.

4.1.3. Installing the OpenShift CLI on Linux

To manage your cluster and deploy applications from the command line on Linux, install the OpenShift CLI (oc) binary. You can download the OpenShift CLI (oc) from the Red  Customer Portal.

Important

If you installed an earlier version of oc, you cannot use it to complete all of the commands in OpenShift Container Platform.

Download and install the new version of oc.

Procedure

  1. Navigate to the Download OpenShift Container Platform page on the Red Hat Customer Portal.
  2. Select the architecture from the Product Variant list.
  3. Select the appropriate version from the Version list.
  4. Click Download Now next to the OpenShift v4.21 Linux Clients entry and save the file.
  5. Unpack the archive:

    $ tar xvf <file>
  6. Place the oc binary in a directory that is on your PATH.

    To check your PATH, run the following command:

    $ echo $PATH

Verification

  • After you install the OpenShift CLI, it is available using the oc command:

    $ oc <command>

4.1.4. Installing the OpenShift CLI on Windows

To manage your cluster and deploy applications from the command line on Windows, install the OpenShift CLI (oc) binary. You can download the OpenShift CLI (oc) from the Red  Customer Portal.

Important

If you installed an earlier version of oc, you cannot use it to complete all of the commands in OpenShift Container Platform.

Download and install the new version of oc.

Procedure

  1. Navigate to the Download OpenShift Container Platform page on the Red Hat Customer Portal.
  2. Select the appropriate version from the Version list.
  3. Click Download Now next to the OpenShift v4.21 Windows Client entry and save the file.
  4. Extract the archive with a ZIP program.
  5. Move the oc binary to a directory that is on your PATH variable.

    To check your PATH variable, open the Command Prompt and run the following command:

    C:\> path

Verification

  • After you install the OpenShift CLI, it is available using the oc command:

    C:\> oc <command>

4.1.5. Installing the OpenShift CLI on macOS

To manage your cluster and deploy applications from the command line on macOS, install the OpenShift CLI (oc) binary. You can download the OpenShift CLI (oc) from the Red  Customer Portal.

Important

If you installed an earlier version of oc, you cannot use it to complete all of the commands in OpenShift Container Platform.

Download and install the new version of oc.

Procedure

  1. Navigate to the Download OpenShift Container Platform page on the Red Hat Customer Portal.
  2. Select the architecture from the Product Variant list.
  3. Select the appropriate version from the Version list.
  4. Click Download Now next to the OpenShift v4.21 macOS Clients entry and save the file.

    Note

    For macOS arm64, choose the OpenShift v4.21 macOS arm64 Client entry.

  5. Extract the archive.
  6. Move the oc binary to a directory on your PATH variable.

    To check your PATH variable, open a terminal and run the following command:

    $ echo $PATH

Verification

  • Verify your installation by using an oc command:

    $ oc <command>

4.1.6. Generating a key pair for cluster node SSH access

During an OpenShift Container Platform installation, you can provide an SSH public key to the installation program. The key is passed to the Red Hat Enterprise Linux CoreOS (RHCOS) nodes through their Ignition config files and is used to authenticate SSH access to the nodes. The key is added to the ~/.ssh/authorized_keys list for the core user on each node, which enables password-less authentication.

The key is added to the ~/.ssh/authorized_keys list for the core user on each node, which enables password-less authentication. After the key is passed to the nodes, you can use the key pair to SSH in to the RHCOS nodes as the user core. To access the nodes through SSH, the private key identity must be managed by SSH for your local user.

If you want to SSH in to your cluster nodes to perform installation debugging or disaster recovery, you must provide the SSH public key during the installation process. The ./openshift-install gather command also requires the SSH public key to be in place on the cluster nodes.

Important

Do not skip this procedure in production environments, where disaster recovery and debugging is required.

Note

You must use a local key, not one that you configured with platform-specific approaches.

Procedure

  1. If you do not have an existing SSH key pair on your local machine to use for authentication onto your cluster nodes, create one. For example, on a computer that uses a Linux operating system, run the following command:

    $ ssh-keygen -t ed25519 -N '' -f <path>/<file_name>

    Specifies the path and file name, such as ~/.ssh/id_ed25519, of the new SSH key. If you have an existing key pair, ensure your public key is in the your ~/.ssh directory.

    Note

    If you plan to install an OpenShift Container Platform cluster that uses the RHEL cryptographic libraries that have been submitted to NIST for FIPS 140-2/140-3 Validation on only the x86_64, ppc64le, and s390x architectures, do not create a key that uses the ed25519 algorithm. Instead, create a key that uses the rsa or ecdsa algorithm.

  2. View the public SSH key:

    $ cat <path>/<file_name>.pub

    For example, run the following to view the ~/.ssh/id_ed25519.pub public key:

    $ cat ~/.ssh/id_ed25519.pub
  3. Add the SSH private key identity to the SSH agent for your local user, if it has not already been added. SSH agent management of the key is required for password-less SSH authentication onto your cluster nodes, or if you want to use the ./openshift-install gather command.

    Note

    On some distributions, default SSH private key identities such as ~/.ssh/id_rsa and ~/.ssh/id_dsa are managed automatically.

    1. If the ssh-agent process is not already running for your local user, start it as a background task:

      $ eval "$(ssh-agent -s)"

      Example output

      Agent pid 31874

      Note

      If your cluster is in FIPS mode, only use FIPS-compliant algorithms to generate the SSH key. The key must be either RSA or ECDSA.

  4. Add your SSH private key to the ssh-agent:

    $ ssh-add <path>/<file_name>

    Specify the path and file name for your SSH private key, such as ~/.ssh/id_ed25519.

    Example output

    Identity added: /home/<you>/<path>/<file_name> (<computer_name>)

Next steps

  • When you install OpenShift Container Platform, provide the SSH public key to the installation program.

4.1.7. Telemetry access for OpenShift Container Platform

To provide metrics about cluster health and the success of updates, the Telemetry service requires internet access. When connected, this service runs automatically by default and registers your cluster to OpenShift Cluster Manager.

After you confirm that your OpenShift Cluster Manager inventory is correct, either maintained automatically by Telemetry or manually by using OpenShift Cluster Manager,use subscription watch to track your OpenShift Container Platform subscriptions at the account or multi-cluster level. For more information about subscription watch, see "Data Gathered and Used by Red Hat’s subscription services" in the Additional resources section.

Before you install OpenShift Container Platform on infrastructure that you provision, ensure that your Amazon Web Services (AWS) environment meets the installation requirements.

For a cluster that has user-provisioned infrastructure, you must deploy all of the required machines.

4.2.1. Required machines for cluster installation

You must specify the minimum required machines or hosts for your cluster so that your cluster remains stable if a node fails.

The smallest OpenShift Container Platform clusters require the following hosts:

Important

For a cluster that has user-provisioned infrastructure, you must deploy all of the required machines.

Table 4.1. Minimum required hosts
HostsDescription

One temporary bootstrap machine

The cluster requires the bootstrap machine to deploy the OpenShift Container Platform cluster on the three control plane machines. You can remove the bootstrap machine after you install the cluster.

Three control plane machines

The control plane machines run the Kubernetes and OpenShift Container Platform services that form the control plane.

At least two compute machines, which are also known as worker machines.

The workloads requested by OpenShift Container Platform users run on the compute machines.

Important

To maintain high availability of your cluster, use separate physical hosts for these cluster machines.

The bootstrap and control plane machines must use Red Hat Enterprise Linux CoreOS (RHCOS) as the operating system. However, the compute machines can use Red Hat Enterprise Linux CoreOS (RHCOS), Red Hat Enterprise Linux (RHEL) 8.6 and later.

RHCOS is based on Red Hat Enterprise Linux (RHEL) 9.2 and inherits all of its hardware certifications and requirements. See Red Hat Enterprise Linux technology capabilities and limits.

4.2.1.1. Minimum resource requirements for cluster installation

To ensure that your OpenShift Container Platform cluster runs as expected, each cluster machine must meet minimum CPU, memory, and storage requirements.

Table 4.2. Minimum resource requirements
MachineOperating systemvCPUVirtual RAMStorageInput/Output Per Second (IOPS)

Bootstrap

RHCOS

4

16 GB

100 GB

300

Control plane

RHCOS

4

16 GB

100 GB

300

Compute

RHCOS

2

8 GB

100 GB

300

  • One vCPU is equal to one physical core when simultaneous multithreading (SMT), or Hyper-Threading, is not enabled. When enabled, use the following formula to calculate the corresponding ratio: (threads per core × cores) × sockets = vCPUs.
  • OpenShift Container Platform and Kubernetes are sensitive to disk performance, and Red Hat recommends faster storage, particularly for etcd on the control plane nodes which require a 10 ms p99 fsync duration. On many cloud platforms, storage size and IOPS scale together, so you might need to provision more storage to get enough performance.
  • As with all user-provisioned installations, if you choose to use RHEL compute machines in your cluster, you take responsibility for all operating system life cycle management and maintenance, including performing system updates, applying patches, and completing all other required tasks. OpenShift Container Platform 4.10 and later do not support RHEL 7 compute machines.
Note

In OpenShift Container Platform version 4.19, RHCOS uses RHEL version 9.6, which updates the micro-architecture requirements. Each architecture requires the following minimum instruction set architectures (ISA):

  • x86-64 architecture requires x86-64-v2 ISA
  • ARM64 architecture requires ARMv8.0-A ISA
  • ppc64le architecture requires IBM® Power9 ISA
  • s390x architecture requires IBM® z14 ISA

For more information, see Architectures in the RHEL documentation.

If an instance type for your platform meets the minimum requirements for cluster machines, it is supported to use in OpenShift Container Platform.

4.2.1.2. Tested instance types for AWS

To ensure cluster stability and performance, use one of the tested Amazon Web Services (AWS) instance types for your OpenShift Container Platform machines.

The following AWS instance types have been tested with OpenShift Container Platform.

Note

Use the machine types included in the following charts for your AWS instances. If you use an instance type that is not listed in the chart, ensure that the instance size you use matches the minimum resource requirements in "Minimum resource requirements for cluster installation".

See the following machine types based on 64-bit x86 architecture:

  • c4.*
  • c5.*
  • c5a.*
  • i3.*
  • m4.*
  • m5.*
  • m5a.*
  • m6a.*
  • m6i.*
  • m7a.*
  • m7i.*
  • m7i-flex.*
  • r4.*
  • r5.*
  • r5a.*
  • r6i.*
  • t3.*
  • t3a.*

4.2.1.3. Tested instance types for AWS on 64-bit ARM infrastructures

To ensure cluster stability and performance, use one of the tested Amazon Web Services (AWS) 64-bit ARM instance types for your OpenShift Container Platform machines.

The following AWS 64-bit ARM instance types have been tested with OpenShift Container Platform.

Note

Use the machine types included in the following charts for your AWS ARM instances. If you use an instance type that is not listed in the chart, ensure that the instance size you use matches the minimum resource requirements listed in "Minimum resource requirements for cluster installation".

See the following machine types based on 64-bit ARM architecture:

  • c6g.*
  • c7g.*
  • c8g.*
  • m6g.*
  • m7g.*
  • m7gd.*
  • r8g.*

4.2.2. Certificate signing requests management

On user-provisioned infrastructure, you must implement a mechanism for approving cluster certificate signing requests (CSRs) after installation when your cluster has limited access to automatic machine management.

The kube-controller-manager only approves the kubelet client CSRs. The machine-approver cannot guarantee the validity of a serving certificate that kubelet credentials request because it cannot confirm that the correct machine issued the request. You must find and implement a method of verifying the validity of the kubelet serving certificate requests and approving them.

4.2.3. Required AWS infrastructure components

To install OpenShift Container Platform on user-provisioned infrastructure in Amazon Web Services (AWS), you must manually create both the machines and their supporting infrastructure.

For more information about the integration testing for different platforms, see the OpenShift Container Platform 4.x Tested Integrations page.

By using the provided CloudFormation templates, you can create stacks of AWS resources that represent the following components:

  • An AWS Virtual Private Cloud (VPC)
  • Networking and load balancing components
  • Security groups and roles
  • An OpenShift Container Platform bootstrap node
  • OpenShift Container Platform control plane nodes
  • An OpenShift Container Platform compute node

Or, you can manually create the components or you can reuse existing infrastructure that meets the cluster requirements. Review the CloudFormation templates for more details about how the components interrelate.

4.2.3.1. Other infrastructure components

Your OpenShift Container Platform cluster on user-provisioned infrastructure in Amazon Web Services (AWS) requires additional infrastructure components, including a VPC, DNS entries, load balancers, security groups, and IAM roles.

  • A VPC
  • DNS entries
  • Load balancers (classic or network) and listeners
  • A public and a private Route 53 zone
  • Security groups
  • IAM roles
  • S3 buckets

If you are working in a disconnected environment, you cannot reach the public IP addresses for EC2, ELB, and S3 endpoints. Depending on the level to which you want to restrict internet traffic during the installation, the following configuration options are available:

4.2.3.1.1. Option 1: Create VPC endpoints

Create a VPC endpoint and attach it to the subnets that the clusters are using. Name the endpoints as follows:

  • ec2.<aws_region>.amazonaws.com
  • elasticloadbalancing.<aws_region>.amazonaws.com
  • s3.<aws_region>.amazonaws.com

With this option, network traffic remains private between your VPC and the required AWS services.

4.2.3.1.2. Option 2: Create a proxy without VPC endpoints

As part of the installation process, you can configure an HTTP or HTTPS proxy. With this option, internet traffic goes through the proxy to reach the required AWS services.

4.2.3.1.3. Option 3: Create a proxy with VPC endpoints

As part of the installation process, you can configure an HTTP or HTTPS proxy with VPC endpoints. Create a VPC endpoint and attach it to the subnets that the clusters are using. Name the endpoints as follows:

  • ec2.<aws_region>.amazonaws.com
  • elasticloadbalancing.<aws_region>.amazonaws.com
  • s3.<aws_region>.amazonaws.com

When configuring the proxy in the install-config.yaml file, add these endpoints to the noProxy field. With this option, the proxy prevents the cluster from accessing the internet directly. However, network traffic remains private between your VPC and the required AWS services.

You must provide a suitable VPC and subnets that allow communication to your machines.

Table 4.3. Required VPC components
ComponentAWS typeDescription

VPC

  • AWS::EC2::VPC
  • AWS::EC2::VPCEndpoint

You must provide a public VPC for the cluster to use. The VPC uses an endpoint that references the route tables for each subnet to improve communication with the registry that is hosted in S3.

Public subnets

  • AWS::EC2::Subnet
  • AWS::EC2::SubnetNetworkAclAssociation

Your VPC must have public subnets for between 1 and 3 availability zones and associate them with appropriate Ingress rules.

Internet gateway

  • AWS::EC2::InternetGateway
  • AWS::EC2::VPCGatewayAttachment
  • AWS::EC2::RouteTable
  • AWS::EC2::Route
  • AWS::EC2::SubnetRouteTableAssociation
  • AWS::EC2::NatGateway
  • AWS::EC2::EIP

You must have a public internet gateway, with public routes, attached to the VPC. In the provided templates, each public subnet has a NAT gateway with an EIP address. These NAT gateways allow cluster resources, such as private subnet instances, to reach the internet and are not required for some restricted network or proxy scenarios.

Network access control

  • AWS::EC2::NetworkAcl
  • AWS::EC2::NetworkAclEntry

You must allow the VPC to access the following ports:

Port

Reason

80

Inbound HTTP traffic

443

Inbound HTTPS traffic

22

Inbound SSH traffic

1024 - 65535

Inbound ephemeral traffic

0 - 65535

Outbound ephemeral traffic

Private subnets

  • AWS::EC2::Subnet
  • AWS::EC2::RouteTable
  • AWS::EC2::SubnetRouteTableAssociation

Your VPC can have private subnets. The provided CloudFormation templates can create private subnets for between 1 and 3 availability zones. If you use private subnets, you must provide appropriate routes and tables for them.

Your DNS and load balancer configuration must use a public hosted zone and can use a private hosted zone similar to the one that the installation program uses if it provisions the cluster’s infrastructure. You must create a DNS entry that resolves to your load balancer. An entry for api.<cluster_name>.<domain> must point to the external load balancer, and an entry for api-int.<cluster_name>.<domain> must point to the internal load balancer.

The cluster also requires load balancers and listeners for port 6443, which the Kubernetes API and its extensions require, and port 22623, which the Ignition config files for new machines require. The targets are the control plane nodes. Port 6443 must be accessible to both clients external to the cluster and nodes within the cluster. Port 22623 must be accessible to nodes within the cluster.

Table 4.4. Required DNS and load balancing components
ComponentAWS typeDescription

DNS

AWS::Route53::HostedZone

The hosted zone for your internal DNS.

Public load balancer

AWS::ElasticLoadBalancingV2::LoadBalancer

The load balancer for your public subnets.

External API server record

AWS::Route53::RecordSetGroup

Alias records for the external API server.

External listener

AWS::ElasticLoadBalancingV2::Listener

A listener on port 6443 for the external load balancer.

External target group

AWS::ElasticLoadBalancingV2::TargetGroup

The target group for the external load balancer.

Private load balancer

AWS::ElasticLoadBalancingV2::LoadBalancer

The load balancer for your private subnets.

Internal API server record

AWS::Route53::RecordSetGroup

Alias records for the internal API server.

Internal listener

AWS::ElasticLoadBalancingV2::Listener

A listener on port 22623 for the internal load balancer.

Internal target group

AWS::ElasticLoadBalancingV2::TargetGroup

The target group for the internal load balancer.

Internal listener

AWS::ElasticLoadBalancingV2::Listener

A listener on port 6443 for the internal load balancer.

Internal target group

AWS::ElasticLoadBalancingV2::TargetGroup

The target group for the internal load balancer.

The control plane and worker machines require access to the following ports:

Table 4.5. Security groups
GroupTypeIP ProtocolPort range

MasterSecurityGroup

AWS::EC2::SecurityGroup

icmp

0

tcp

22

tcp

6443

tcp

22623

WorkerSecurityGroup

AWS::EC2::SecurityGroup

icmp

0

tcp

22

BootstrapSecurityGroup

AWS::EC2::SecurityGroup

tcp

22

tcp

19531

The control plane machines require the following Ingress groups. Each Ingress group is an AWS::EC2::SecurityGroupIngress resource.

Table 4.6. Control plane Ingress
Ingress groupDescriptionIP protocolPort range

MasterIngressEtcd

etcd

tcp

2379- 2380

MasterIngressVxlan

Vxlan packets

udp

6081

MasterIngressWorkerVxlan

Vxlan packets

udp

6081

MasterIngressInternal

Internal cluster communication and Kubernetes proxy metrics

tcp

9000 - 9999

MasterIngressWorkerInternal

Internal cluster communication

tcp

9000 - 9999

MasterIngressKube

Kubernetes kubelet, scheduler and controller manager

tcp

10250 - 10259

MasterIngressWorkerKube

Kubernetes kubelet, scheduler and controller manager

tcp

10250 - 10259

MasterIngressIngressServices

Kubernetes Ingress services

tcp

30000 - 32767

MasterIngressWorkerIngressServices

Kubernetes Ingress services

tcp

30000 - 32767

MasterIngressGeneve

Geneve packets

udp

6081

MasterIngressWorkerGeneve

Geneve packets

udp

6081

MasterIngressIpsecIke

IPsec IKE packets

udp

500

MasterIngressWorkerIpsecIke

IPsec IKE packets

udp

500

MasterIngressIpsecNat

IPsec NAT-T packets

udp

4500

MasterIngressWorkerIpsecNat

IPsec NAT-T packets

udp

4500

MasterIngressIpsecEsp

IPsec ESP packets

50

All

MasterIngressWorkerIpsecEsp

IPsec ESP packets

50

All

MasterIngressInternalUDP

Internal cluster communication

udp

9000 - 9999

MasterIngressWorkerInternalUDP

Internal cluster communication

udp

9000 - 9999

MasterIngressIngressServicesUDP

Kubernetes Ingress services

udp

30000 - 32767

MasterIngressWorkerIngressServicesUDP

Kubernetes Ingress services

udp

30000 - 32767

The worker machines require the following Ingress groups. Each Ingress group is an AWS::EC2::SecurityGroupIngress resource.

Table 4.7. Worker Ingress
Ingress groupDescriptionIP protocolPort range

WorkerIngressVxlan

Vxlan packets

udp

6081

WorkerIngressWorkerVxlan

Vxlan packets

udp

6081

WorkerIngressInternal

Internal cluster communication

tcp

9000 - 9999

WorkerIngressWorkerInternal

Internal cluster communication

tcp

9000 - 9999

WorkerIngressKube

Kubernetes kubelet, scheduler, and controller manager

tcp

10250

WorkerIngressWorkerKube

Kubernetes kubelet, scheduler, and controller manager

tcp

10250

WorkerIngressIngressServices

Kubernetes Ingress services

tcp

30000 - 32767

WorkerIngressWorkerIngressServices

Kubernetes Ingress services

tcp

30000 - 32767

WorkerIngressGeneve

Geneve packets

udp

6081

WorkerIngressMasterGeneve

Geneve packets

udp

6081

WorkerIngressIpsecIke

IPsec IKE packets

udp

500

WorkerIngressMasterIpsecIke

IPsec IKE packets

udp

500

WorkerIngressIpsecNat

IPsec NAT-T packets

udp

4500

WorkerIngressMasterIpsecNat

IPsec NAT-T packets

udp

4500

WorkerIngressIpsecEsp

IPsec ESP packets

50

All

WorkerIngressMasterIpsecEsp

IPsec ESP packets

50

All

WorkerIngressInternalUDP

Internal cluster communication

udp

9000 - 9999

WorkerIngressMasterInternalUDP

Internal cluster communication

udp

9000 - 9999

WorkerIngressIngressServicesUDP

Kubernetes Ingress services

udp

30000 - 32767

WorkerIngressMasterIngressServicesUDP

Kubernetes Ingress services

udp

30000 - 32767

You must grant the machines permissions in AWS. The provided CloudFormation templates grant the machines Allow permissions for the following AWS::IAM::Role objects and provide an AWS::IAM::InstanceProfile for each set of roles. If you do not use the templates, you can grant the machines the following broad permissions or the following individual permissions.

Table 4.8. Roles and instance profiles
RoleEffectActionResource

Control plane

Allow

ec2:*

*

Allow

elasticloadbalancing:*

*

Allow

iam:PassRole

*

Allow

s3:GetObject

*

Worker

Allow

ec2:Describe*

*

Bootstrap

Allow

ec2:Describe*

*

Allow

ec2:AttachVolume

*

Allow

ec2:DetachVolume

*

4.2.3.2. Cluster machines

Your OpenShift Container Platform cluster on user-provisioned infrastructure requires AWS::EC2::Instance objects for bootstrap, control plane, and compute machines.

You need AWS::EC2::Instance objects for the following machines:

  • A bootstrap machine. This machine is required during installation, but you can remove it after your cluster deploys.
  • Three control plane machines. A control plane machine set does not govern the control plane machines.
  • Compute machines. You must create at least two compute machines, which are also known as worker machines, during installation. A compute machine set does not govern these machines.

4.2.4. Required AWS permissions for the IAM user

To deploy all components of an OpenShift Container Platform cluster, you must grant all the required permissions to the IAM user that you create in Amazon Web Services (AWS).

Note

Your IAM user must have the permission tag:GetResources in the region us-east-1 to delete the base cluster resources. As part of the AWS API requirement, the OpenShift Container Platform installation program performs various actions in this region.

When you attach the AdministratorAccess policy to the IAM user that you create in AWS, you grant that user all of the required permissions. To deploy all components of an OpenShift Container Platform cluster, the IAM user requires the following permissions:

Required EC2 permissions for installation

  • ec2:AttachNetworkInterface
  • ec2:AuthorizeSecurityGroupEgress
  • ec2:AuthorizeSecurityGroupIngress
  • ec2:CopyImage
  • ec2:CreateNetworkInterface
  • ec2:CreateSecurityGroup
  • ec2:CreateTags
  • ec2:CreateVolume
  • ec2:DeleteSecurityGroup
  • ec2:DeleteSnapshot
  • ec2:DeleteTags
  • ec2:DeregisterImage
  • ec2:DescribeAccountAttributes
  • ec2:DescribeAddresses
  • ec2:DescribeAvailabilityZones
  • ec2:DescribeDhcpOptions
  • ec2:DescribeImages
  • ec2:DescribeInstanceAttribute
  • ec2:DescribeInstanceCreditSpecifications
  • ec2:DescribeInstances
  • ec2:DescribeInstanceTypes
  • ec2:DescribeInstanceTypeOfferings
  • ec2:DescribeInternetGateways
  • ec2:DescribeKeyPairs
  • ec2:DescribeNatGateways
  • ec2:DescribeNetworkAcls
  • ec2:DescribeNetworkInterfaces
  • ec2:DescribePrefixLists
  • ec2:DescribePublicIpv4Pools (only required if you specify publicIpv4Pool in install-config.yaml)
  • ec2:DescribeRegions
  • ec2:DescribeRouteTables
  • ec2:DescribeSecurityGroupRules
  • ec2:DescribeSecurityGroups
  • ec2:DescribeSubnets
  • ec2:DescribeTags
  • ec2:DescribeVolumes
  • ec2:DescribeVpcAttribute
  • ec2:DescribeVpcClassicLink
  • ec2:DescribeVpcClassicLinkDnsSupport
  • ec2:DescribeVpcEndpoints
  • ec2:DescribeVpcs
  • ec2:DisassociateAddress (only required if you specify publicIpv4Pool in install-config.yaml)
  • ec2:GetEbsDefaultKmsKeyId
  • ec2:ModifyInstanceAttribute
  • ec2:ModifyNetworkInterfaceAttribute
  • ec2:RevokeSecurityGroupEgress
  • ec2:RevokeSecurityGroupIngress
  • ec2:RunInstances
  • ec2:TerminateInstances

Required permissions for creating network resources during installation

  • ec2:AllocateAddress
  • ec2:AssociateAddress
  • ec2:AssociateDhcpOptions
  • ec2:AssociateRouteTable
  • ec2:AttachInternetGateway
  • ec2:CreateDhcpOptions
  • ec2:CreateInternetGateway
  • ec2:CreateNatGateway
  • ec2:CreateRoute
  • ec2:CreateRouteTable
  • ec2:CreateSubnet
  • ec2:CreateVpc
  • ec2:CreateVpcEndpoint
  • ec2:ModifySubnetAttribute
  • ec2:ModifyVpcAttribute
Note

If you use an existing Virtual Private Cloud (VPC), your account does not require these permissions for creating network resources.

Required Elastic Load Balancing permissions (ELB) for installation

  • elasticloadbalancing:AddTags
  • elasticloadbalancing:ApplySecurityGroupsToLoadBalancer
  • elasticloadbalancing:AttachLoadBalancerToSubnets
  • elasticloadbalancing:ConfigureHealthCheck
  • elasticloadbalancing:CreateListener
  • elasticloadbalancing:CreateLoadBalancer
  • elasticloadbalancing:CreateLoadBalancerListeners
  • elasticloadbalancing:CreateTargetGroup
  • elasticloadbalancing:DeleteLoadBalancer
  • elasticloadbalancing:DeregisterInstancesFromLoadBalancer
  • elasticloadbalancing:DeregisterTargets
  • elasticloadbalancing:DescribeInstanceHealth
  • elasticloadbalancing:DescribeListeners
  • elasticloadbalancing:DescribeLoadBalancerAttributes
  • elasticloadbalancing:DescribeLoadBalancers
  • elasticloadbalancing:DescribeTags
  • elasticloadbalancing:DescribeTargetGroupAttributes
  • elasticloadbalancing:DescribeTargetHealth
  • elasticloadbalancing:ModifyLoadBalancerAttributes
  • elasticloadbalancing:ModifyTargetGroup
  • elasticloadbalancing:ModifyTargetGroupAttributes
  • elasticloadbalancing:RegisterInstancesWithLoadBalancer
  • elasticloadbalancing:RegisterTargets
  • elasticloadbalancing:SetLoadBalancerPoliciesOfListener
  • elasticloadbalancing:SetSecurityGroups
Important

OpenShift Container Platform uses both the ELB and ELBv2 API services to provision load balancers. The permission list shows permissions required by both services. A known issue exists in the AWS web console where both services use the same elasticloadbalancing action prefix but do not recognize the same actions. You can ignore the warnings about the service not recognizing certain elasticloadbalancing actions.

Required IAM permissions for installation

  • iam:AddRoleToInstanceProfile
  • iam:CreateInstanceProfile
  • iam:CreateRole
  • iam:DeleteInstanceProfile
  • iam:DeleteRole
  • iam:DeleteRolePolicy
  • iam:GetInstanceProfile
  • iam:GetRole
  • iam:GetRolePolicy
  • iam:GetUser
  • iam:ListInstanceProfilesForRole
  • iam:ListRoles
  • iam:ListUsers
  • iam:PassRole
  • iam:PutRolePolicy
  • iam:RemoveRoleFromInstanceProfile
  • iam:SimulatePrincipalPolicy
  • iam:TagInstanceProfile
  • iam:TagRole
Note
  • If you specify an existing IAM role in the install-config.yaml file, the following IAM permissions are not required: iam:CreateRole,iam:DeleteRole, iam:DeleteRolePolicy, and iam:PutRolePolicy.
  • If you have not created a load balancer in your AWS account, the IAM user also requires the iam:CreateServiceLinkedRole permission.

Required Route 53 permissions for installation

  • route53:ChangeResourceRecordSets
  • route53:ChangeTagsForResource
  • route53:CreateHostedZone
  • route53:DeleteHostedZone
  • route53:GetChange
  • route53:GetHostedZone
  • route53:ListHostedZones
  • route53:ListHostedZonesByName
  • route53:ListResourceRecordSets
  • route53:ListTagsForResource
  • route53:UpdateHostedZoneComment

Required Amazon Simple Storage Service (S3) permissions for installation

  • s3:CreateBucket
  • s3:DeleteBucket
  • s3:GetAccelerateConfiguration
  • s3:GetBucketAcl
  • s3:GetBucketCors
  • s3:GetBucketLocation
  • s3:GetBucketLogging
  • s3:GetBucketObjectLockConfiguration
  • s3:GetBucketPolicy
  • s3:GetBucketRequestPayment
  • s3:GetBucketTagging
  • s3:GetBucketVersioning
  • s3:GetBucketWebsite
  • s3:GetEncryptionConfiguration
  • s3:GetLifecycleConfiguration
  • s3:GetReplicationConfiguration
  • s3:ListBucket
  • s3:PutBucketAcl
  • s3:PutBucketPolicy
  • s3:PutBucketTagging
  • s3:PutEncryptionConfiguration

S3 permissions that cluster Operators require

  • s3:DeleteObject
  • s3:GetObject
  • s3:GetObjectAcl
  • s3:GetObjectTagging
  • s3:GetObjectVersion
  • s3:PutObject
  • s3:PutObjectAcl
  • s3:PutObjectTagging

Required permissions to delete base cluster resources

  • autoscaling:DescribeAutoScalingGroups
  • ec2:DeleteNetworkInterface
  • ec2:DeletePlacementGroup
  • ec2:DeleteVolume
  • elasticloadbalancing:DeleteTargetGroup
  • elasticloadbalancing:DescribeTargetGroups
  • iam:DeleteAccessKey
  • iam:DeleteUser
  • iam:DeleteUserPolicy
  • iam:ListAttachedRolePolicies
  • iam:ListInstanceProfiles
  • iam:ListRolePolicies
  • iam:ListUserPolicies
  • s3:DeleteObject
  • s3:ListBucketVersions
  • tag:GetResources

Required permissions to delete network resources

  • ec2:DeleteDhcpOptions
  • ec2:DeleteInternetGateway
  • ec2:DeleteNatGateway
  • ec2:DeleteRoute
  • ec2:DeleteRouteTable
  • ec2:DeleteSubnet
  • ec2:DeleteVpc
  • ec2:DeleteVpcEndpoints
  • ec2:DetachInternetGateway
  • ec2:DisassociateRouteTable
  • ec2:ReleaseAddress
  • ec2:ReplaceRouteTableAssociation
Note

If you use an existing VPC, your account does not require these permissions to delete network resources. Instead, your account only requires the tag:UntagResources permission to delete network resources.

Optional permissions for installing a cluster with a custom Key Management Service (KMS) key

  • kms:CreateGrant
  • kms:Decrypt
  • kms:DescribeKey
  • kms:Encrypt
  • kms:GenerateDataKey
  • kms:GenerateDataKeyWithoutPlainText
  • kms:ListGrants
  • kms:RevokeGrant
Note

If you use an Amazon Machine Image (AMI) encrypted with a customer-managed key, you must grant the kms:ReEncrypt* permissions in addition to these permissions.

Required permissions to delete a cluster with shared instance roles

  • iam:UntagRole

Required permissions to delete a cluster with shared instance profiles

  • tag:UntagResources

Additional IAM and S3 permissions required to create manifests

  • iam:GetUserPolicy
  • iam:ListAccessKeys
  • iam:PutUserPolicy
  • iam:TagUser
  • s3:AbortMultipartUpload
  • s3:GetBucketPublicAccessBlock
  • s3:ListBucket
  • s3:ListBucketMultipartUploads
  • s3:PutBucketPublicAccessBlock
  • s3:PutLifecycleConfiguration
Note

If you are managing your cloud provider credentials with mint mode, the IAM user also requires the iam:CreateAccessKey and iam:CreateUser permissions.

Optional permissions for instance and quota checks for installation

  • servicequotas:ListAWSDefaultServiceQuotas

Optional permissions for the cluster owner account when installing a cluster on a shared VPC

  • sts:AssumeRole

Required permissions for enabling Bring your own public IPv4 addresses (BYOIP) feature for installation

  • ec2:DescribePublicIpv4Pools
  • ec2:DisassociateAddress

4.2.5. Obtaining an AWS Marketplace image

If you are deploying an OpenShift Container Platform cluster by using an Amazon Web Services (AWS) Marketplace image, you must first subscribe through AWS. Subscribing to the offer provides you with the Amazon Machine Image (AMI) ID that the installation program uses to deploy compute nodes.

Note

You should only modify the RHCOS image for compute machines to use an AWS Marketplace image. Control plane machines and infrastructure nodes do not require an OpenShift Container Platform subscription and use the public RHCOS default image by default, which does not incur subscription costs on your AWS bill. Therefore, you should not modify the cluster default boot image or the control plane boot images. Applying the AWS Marketplace image to them will incur additional licensing costs that cannot be recovered.

Prerequisites

  • You have an AWS account to buy the offer. This account does not have to be the same account that you use to install the cluster.

Procedure

  1. Complete the OpenShift Container Platform subscription from the AWS Marketplace.

To deploy OpenShift Container Platform version 4.21 on Amazon Web Services (AWS) with your own infrastructure, use the CloudFormation templates or create resources according to your company’s policies.

One way to create this infrastructure is to use the CloudFormation templates. You can change the templates to customize your infrastructure or use the information that they contain to create AWS objects according to your company’s policies.

Important

The steps for performing a user-provisioned infrastructure installation are an example only. Installing a cluster with your own infrastructure requires knowledge of the cloud provider and the installation process of OpenShift Container Platform. Several CloudFormation templates are available to assist in completing these steps or to help model your own. You are also free to create the required resources through other methods; the templates are just an example.

4.3.1. Prerequisites

  • You reviewed details about the OpenShift Container Platform installation and update processes.
  • You read the documentation on selecting a cluster installation method and preparing it for users.
  • You configured an AWS account to host the cluster.

    Important

    If you have an AWS profile stored on your computer, it must not use a temporary session token that you generated while using a multifactor authentication device. The cluster continues to use your current AWS credentials to create AWS resources for the entire life of the cluster, so you must use key-based, long-term credentials. To generate appropriate keys, see Managing Access Keys for IAM Users in the AWS documentation. You can supply the keys when you run the installation program.

  • You prepared the user-provisioned infrastructure.
  • You downloaded the AWS CLI and installed it on your computer.
  • If you use a firewall, you configured it to allow the sites that your cluster requires access to.

    Note

    Be sure to also review this site list if you are configuring a proxy.

  • If the cloud identity and access management (IAM) APIs are not accessible in your environment, or if you do not want to store an administrator-level credential secret in the kube-system namespace, you can manually create and keep long-term credentials.

4.3.2. Creating the installation files for AWS

To install OpenShift Container Platform on Amazon Web Services by using user-provisioned infrastructure, you must generate the files that the installation program needs to deploy your cluster and modify them so that the cluster creates only the machines that it will use.

You generate and customize the install-config.yaml file, Kubernetes manifests, and Ignition config files. You also have the option to first set up a separate var partition during the preparation phases of installation.

4.3.2.1. Creating a separate /var partition

To isolate growing storage for containers, etcd, or logs, you can optionally create a separate /var partition on worker nodes before you generate Ignition configs.

It is recommended that disk partitioning for OpenShift Container Platform be left to the installation program. However, there are cases where you might want to create separate partitions in a part of the filesystem that you expect to grow.

OpenShift Container Platform supports the addition of a single partition to attach storage to either the /var partition or a subdirectory of /var. For example:

  • /var/lib/containers: Holds container-related content that can grow as more images and containers are added to a system.
  • /var/lib/etcd: Holds data that you might want to keep separate for purposes such as performance optimization of etcd storage.
  • /var: Holds data that you might want to keep separate for purposes such as auditing.

Storing the contents of a /var directory separately makes it easier to grow storage for those areas as needed and reinstall OpenShift Container Platform at a later date and keep that data intact. With this method, you will not have to pull all your containers again, nor will you have to copy massive log files when you update systems.

Because /var must be in place before a fresh installation of Red Hat Enterprise Linux CoreOS (RHCOS), the following procedure sets up the separate /var partition by creating a machine config manifest that is inserted during the openshift-install preparation phases of an OpenShift Container Platform installation.

Important

If you follow the steps to create a separate /var partition in this procedure, it is not necessary to create the Kubernetes manifest and Ignition config files again as described later in this section.

Procedure

  1. Create a directory to hold the OpenShift Container Platform installation files:

    $ mkdir $HOME/clusterconfig
  2. Run openshift-install to create a set of files in the manifest and openshift subdirectories. Answer the system questions as you are prompted:

    $ openshift-install create manifests --dir $HOME/clusterconfig

    Example output

    ? SSH Public Key ...
    INFO Credentials loaded from the "myprofile" profile in file "/home/myuser/.aws/credentials"
    INFO Consuming Install Config from target directory
    INFO Manifests created in: $HOME/clusterconfig/manifests and $HOME/clusterconfig/openshift

  3. Optional: Confirm that the installation program created manifests in the clusterconfig/openshift directory:

    $ ls $HOME/clusterconfig/openshift/

    Example output

    99_kubeadmin-password-secret.yaml
    99_openshift-cluster-api_master-machines-0.yaml
    99_openshift-cluster-api_master-machines-1.yaml
    99_openshift-cluster-api_master-machines-2.yaml
    ...

  4. Create a Butane config that configures the additional partition. For example, name the file $HOME/clusterconfig/98-var-partition.bu, change the disk device name to the name of the storage device on the worker systems, and set the storage size as appropriate. This example places the /var directory on a separate partition:

    variant: openshift
    version: 4.21.0
    metadata:
      labels:
        machineconfiguration.openshift.io/role: worker
      name: 98-var-partition
    storage:
      disks:
      - device: /dev/disk/by-id/<device_name>
        partitions:
        - label: var
          start_mib: <partition_start_offset>
          size_mib: <partition_size>
          number: 5
      filesystems:
        - device: /dev/disk/by-partlabel/var
          path: /var
          format: xfs
          mount_options: [defaults, prjquota]
          with_mount_unit: true

    where:

    <device_name>
    Specifies the storage device name of the disk that you want to partition.
    <partition_start_offset>
    Specifies the start_mib parameter. When adding a data partition to the boot disk, a minimum value of 25000 MiB (Mebibytes) is recommended. The root file system is automatically resized to fill all available space up to the specified offset. If no value is specified, or if the specified value is smaller than the recommended minimum, the resulting root file system will be too small, and future reinstalls of RHCOS might overwrite the beginning of the data partition.
    <partition_size>
    Specifies the size of the data partition in mebibytes.
    storage.filesystems.mount_options

    The prjquota mount option must be enabled for filesystems used for container storage.

    Note

    When creating a separate /var partition, you cannot use different instance types for worker nodes, if the different instance types do not have the same device name.

  5. Create a manifest from the Butane config and save it to the clusterconfig/openshift directory. For example, run the following command:

    $ butane $HOME/clusterconfig/98-var-partition.bu -o $HOME/clusterconfig/openshift/98-var-partition.yaml
  6. Run openshift-install again to create Ignition configs from a set of files in the manifest and openshift subdirectories:

    $ openshift-install create ignition-configs --dir $HOME/clusterconfig
    $ ls $HOME/clusterconfig/
    auth  bootstrap.ign  master.ign  metadata.json  worker.ign

    You can now use the Ignition config files as input to the installation procedures to install Red Hat Enterprise Linux CoreOS (RHCOS) systems.

4.3.2.2. Creating the installation configuration file

Generate and customize the installation configuration file that the installation program needs to deploy your cluster.

Prerequisites

  • You obtained the OpenShift Container Platform installation program for user-provisioned infrastructure and the pull secret for your cluster.
  • You checked that you are deploying your cluster to an Amazon Web Services (AWS) Region with an accompanying Red Hat Enterprise Linux CoreOS (RHCOS) AMI published by Red Hat. If you are deploying to an AWS Region that requires a custom AMI, such as an AWS GovCloud Region, you must create the install-config.yaml file manually.

Procedure

  1. Create the install-config.yaml file.

    1. Change to the directory that contains the installation program and run the following command:

      $ ./openshift-install create install-config --dir <installation_directory>

      For <installation_directory>, specify the directory name to store the files that the installation program creates.

      Important

      Specify an empty directory. Some installation assets, such as bootstrap X.509 certificates have short expiration intervals, so you must not reuse an installation directory. If you want to reuse individual files from another cluster installation, you can copy them into your directory. However, the file names for the installation assets might change between releases. Use caution when copying installation files from an earlier OpenShift Container Platform version.

    2. At the prompts, provide the configuration details for your cloud:

      1. Optional: Select an SSH key to use to access your cluster machines.

        Note

        For production OpenShift Container Platform clusters on which you want to perform installation debugging or disaster recovery, specify an SSH key that your ssh-agent process uses.

      2. Select aws as the platform to target.
      3. If you do not have an AWS profile stored on your computer, enter the AWS access key ID and secret access key for the user that you configured to run the installation program.

        Note

        The AWS access key ID and secret access key are stored in ~/.aws/credentials in the home directory of the current user on the installation host. You are prompted for the credentials by the installation program if the credentials for the exported profile are not present in the file. Any credentials that you provide to the installation program are stored in the file.

      4. Select the AWS Region to deploy the cluster to.
      5. Select the base domain for the Route 53 service that you configured for your cluster.
      6. Enter a descriptive name for your cluster.
      7. Paste the pull secret from Red Hat OpenShift Cluster Manager.
  2. If you are installing a three-node cluster, modify the install-config.yaml file by setting the compute.replicas parameter to 0. This ensures that the cluster’s control planes are schedulable. For more information, see "Installing a three-node cluster on AWS".
  3. Optional: Back up the install-config.yaml file.

    Important

    The install-config.yaml file is consumed during the installation process. If you want to reuse the file, you must back it up now.

4.3.2.3. Configuring the cluster-wide proxy during installation

Production environments can deny direct access to the internet and instead have an HTTP or HTTPS proxy available. You can configure a new OpenShift Container Platform cluster to use a proxy by configuring the proxy settings in the install-config.yaml file.

Prerequisites

  • You have an existing install-config.yaml file.
  • You have reviewed the sites that your cluster requires access to and determined whether any of them need to bypass the proxy. By default, the proxy handles all cluster egress traffic, including calls to hosting cloud provider APIs. You added sites to the Proxy object’s spec.noProxy field to bypass the proxy if necessary.

    Note

    The Proxy object status.noProxy field includes the values of the networking.machineNetwork[].cidr, networking.clusterNetwork[].cidr, and networking.serviceNetwork[] fields from your installation configuration.

    For installations on Amazon Web Services (AWS), Google Cloud, Microsoft Azure, and Red Hat OpenStack Platform (RHOSP), the Proxy object status.noProxy field also includes the instance metadata endpoint (169.254.169.254).

Procedure

  1. Edit your install-config.yaml file and add the proxy settings. For example:

    apiVersion: v1
    baseDomain: my.domain.com
    proxy:
      httpProxy: http://<username>:<pswd>@<ip>:<port>
      httpsProxy: https://<username>:<pswd>@<ip>:<port>
      noProxy: ec2.<aws_region>.amazonaws.com,elasticloadbalancing.<aws_region>.amazonaws.com,s3.<aws_region>.amazonaws.com
    additionalTrustBundle: |
        -----BEGIN CERTIFICATE-----
        <MY_TRUSTED_CA_CERT>
        -----END CERTIFICATE-----
    additionalTrustBundlePolicy: <policy_to_add_additionalTrustBundle>
    # ...

    where:

    proxy.httpProxy
    Specifies a proxy URL to use for creating HTTP connections outside the cluster. The URL scheme must be http.
    proxy.httpsProxy
    Specifies a proxy URL to use for creating HTTPS connections outside the cluster.
    proxy.noProxy
    Specifies a comma-separated list of destination domain names, IP addresses, or other network CIDRs to exclude from proxying. Preface a domain with . to match subdomains only. For example, .y.com matches x.y.com, but not y.com. Use * to bypass the proxy for all destinations. If you have added the Amazon EC2, Elastic Load Balancing, and S3 VPC endpoints to your VPC, you must add these endpoints to the noProxy field.
    additionalTrustBundle
    If you specify this value, the installation program generates a config map named user-ca-bundle in the openshift-config namespace to hold the additional CA certificates. If you specify additionalTrustBundle and at least one proxy setting, the Proxy object references the user-ca-bundle config map in the trustedCA field. The Cluster Network Operator then creates a trusted-ca-bundle config map that merges the contents specified for the trustedCA parameter with the RHCOS trust bundle. You must set the additionalTrustBundle field unless an authority from the RHCOS trust bundle signs the proxy’s identity certificate.
    additionalTrustBundlePolicy

    Specifies the policy that determines the configuration of the Proxy object to reference the user-ca-bundle config map in the trustedCA field. The allowed values are Proxyonly and Always. Use Proxyonly to reference the user-ca-bundle config map only when you configure an http/https proxy. Use Always to always reference the user-ca-bundle config map. The default value is Proxyonly. Optional parameter.

    Note

    The installation program does not support the proxy readinessEndpoints field.

    Note

    If the installation program times out, restart and then complete the deployment by using the wait-for command of the installation program. For example:

    $ ./openshift-install wait-for install-complete --log-level debug
  2. Save the file and reference it when installing OpenShift Container Platform.

    The installation program creates a cluster-wide proxy named cluster that uses the proxy settings in the install-config.yaml file. If you do not give proxy settings, the installation program still creates a cluster Proxy object, but it has a nil spec.

    Note

    Only the Proxy object named cluster is supported, and you cannot create additional proxies.

4.3.2.4. Creating the Kubernetes manifest and Ignition config files

Because you manually provision infrastructure, you must generate the Kubernetes manifest and Ignition config files that the cluster requires.

The installation program converts the installation configuration into Kubernetes manifests and then wraps them into Ignition configuration files. You use these Ignition files to configure the cluster machines.

Important
  • The Ignition config files that the OpenShift Container Platform installation program generates contain certificates that expire after 24 hours, which the system then renews. If you shut down the cluster before the system renews the certificates and you later restart the cluster after the 24 hours have elapsed, the cluster automatically recovers the expired certificates. The exception is that you must manually approve the pending node-bootstrapper certificate signing requests (CSRs) to recover kubelet certificates. See the documentation for Recovering from expired control plane certificates for more information.
  • Use Ignition config files within 12 hours after you generate them, because the 24-hour certificate rotates from 16 to 22 hours after you install the cluster. By using the Ignition config files within 12 hours, you can avoid installation failure if the certificate update runs during installation.

Prerequisites

  • You obtained the OpenShift Container Platform installation program.
  • You created the install-config.yaml installation configuration file.

Procedure

  1. Change to the directory that contains the OpenShift Container Platform installation program and generate the Kubernetes manifests for the cluster:

    $ ./openshift-install create manifests --dir <installation_directory>

    where:

    <installation_directory>
    Specifies the installation directory that contains the install-config.yaml file you created.
  2. Remove the Kubernetes manifest files that define the control plane machines:

    $ rm -f <installation_directory>/openshift/99_openshift-cluster-api_master-machines-*.yaml

    By removing these files, you prevent the cluster from automatically generating control plane machines.

  3. Remove the Kubernetes manifest files that define the control plane machine set:

    $ rm -f <installation_directory>/openshift/99_openshift-machine-api_master-control-plane-machine-set.yaml
  4. Remove the Kubernetes manifest files that define the worker machines:

    $ rm -f <installation_directory>/openshift/99_openshift-cluster-api_worker-machineset-*.yaml
    Important

    If you disabled the MachineAPI capability when installing a cluster on user-provisioned infrastructure, you must remove the Kubernetes manifest files that define the worker machines. Otherwise, your cluster fails to install.

    Because you create and manage the worker machines yourself, you do not need to initialize these machines.

    Warning

    If you are installing a three-node cluster, skip the following step to allow the control plane nodes to be schedulable.

    Important

    When you configure control plane nodes from the default unschedulable to schedulable, you require additional subscriptions because control plane nodes then become compute nodes.

  5. Verify that the mastersSchedulable parameter in the <installation_directory>/manifests/cluster-scheduler-02-config.yml Kubernetes manifest file is set to false. This setting prevents pods from being scheduled on the control plane machines:

    1. Open the <installation_directory>/manifests/cluster-scheduler-02-config.yml file.
    2. Locate the mastersSchedulable parameter and verify that it is set to false.
    3. Save and exit the file.
  6. Optional: If you do not want the Ingress Operator to create DNS records on your behalf, remove the privateZone and publicZone sections from the <installation_directory>/manifests/cluster-dns-02-config.yml DNS configuration file:

    apiVersion: config.openshift.io/v1
    kind: DNS
    metadata:
      creationTimestamp: null
      name: cluster
    spec:
      baseDomain: example.openshift.com
      privateZone:
        id: mycluster-100419-private-zone
      publicZone:
        id: example.openshift.com
    status: {}

    spec.privateZone: Remove this section completely.

    If you do so, you must add ingress DNS records manually in a later step.

  7. To create the Ignition configuration files, run the following command from the directory that contains the installation program:

    $ ./openshift-install create ignition-configs --dir <installation_directory>

    where:

    <installation_directory>

    Specifies the same installation directory.

    The installation program creates Ignition config files for the bootstrap, control plane, and compute nodes in the installation directory. The program also creates the kubeadmin-password and kubeconfig files in the ./<installation_directory>/auth directory:

    .
    ├── auth
    │   ├── kubeadmin-password
    │   └── kubeconfig
    ├── bootstrap.ign
    ├── master.ign
    ├── metadata.json
    └── worker.ign

4.3.3. Extracting the infrastructure name

To identify your cluster resources in Amazon Web Services, extract the unique infrastructure name from the Ignition config files.

The Ignition config files contain a unique cluster identifier that you can use to uniquely identify your cluster in Amazon Web Services. The infrastructure name is also used to locate the appropriate AWS resources during an OpenShift Container Platform installation. The provided CloudFormation templates contain references to this infrastructure name, so you must extract it.

Prerequisites

  • You obtained the OpenShift Container Platform installation program and the pull secret for your cluster.
  • You generated the Ignition config files for your cluster.
  • You installed the jq package.

Procedure

  • To extract and view the infrastructure name from the Ignition config file metadata, run the following command:

    $ jq -r .infraID <installation_directory>/metadata.json

    where <installation_directory> is the path to the directory that you stored the installation files in.

    Example output

    openshift-vw9j6

    The output of this command is your cluster name and a random string.

4.3.4. Creating a VPC in AWS

To provide the network foundation for your OpenShift Container Platform cluster, create a Virtual Private Cloud (VPC) in Amazon Web Services (AWS) by using the provided CloudFormation template.

You can customize the VPC to meet your requirements, including VPN and route tables. You can use the provided CloudFormation template and a custom parameter file to create a stack of AWS resources that represent the VPC.

Note

If you do not use the provided CloudFormation template to create your AWS infrastructure, you must review the provided information and manually create the infrastructure. If your cluster does not initialize correctly, you might have to contact Red Hat support with your installation logs.

Prerequisites

  • You added your AWS keys and region to your local AWS profile by running aws configure.

Procedure

  1. Create a JSON file that contains the parameter values that the template requires:

    [
      {
        "ParameterKey": "VpcCidr",
        "ParameterValue": "10.0.0.0/16"
      },
      {
        "ParameterKey": "AvailabilityZoneCount",
        "ParameterValue": "1"
      },
      {
        "ParameterKey": "SubnetBits",
        "ParameterValue": "12"
      }
    ]

    where:

    VpcCidr
    Specifies the CIDR block for the VPC in the format x.x.x.x/16-24.
    AvailabilityZoneCount
    Specifies the number of availability zones to deploy the VPC in. Set the value to an integer between 1 and 3.
    SubnetBits
    Specifies the size of each subnet in each availability zone. Set the value to an integer between 5 and 13, where 5 is /27 and 13 is /19.
  2. Copy the template from the CloudFormation template for the VPC section of this topic and save it as a YAML file on your computer. This template describes the VPC that your cluster requires.
  3. Launch the CloudFormation template to create a stack of AWS resources that represent the VPC:

    Important

    You must enter the command on a single line.

    $ aws cloudformation create-stack --stack-name <name> \
         --template-body file://<template>.yaml \
         --parameters file://<parameters>.json

    where:

    <name>
    Specifies the name for the CloudFormation stack, such as cluster-vpc. You need the name of this stack if you remove the cluster.
    <template>
    Specifies the relative path to and name of the CloudFormation template YAML file that you saved.
    <parameters>
    Specifies the relative path to and name of the CloudFormation parameters JSON file.

    Example output

    arn:aws:cloudformation:us-east-1:269333783861:stack/cluster-vpc/dbedae40-2fd3-11eb-820e-12a48460849f

  4. Confirm that the template components exist:

    $ aws cloudformation describe-stacks --stack-name <name>

    After the StackStatus displays CREATE_COMPLETE, the output displays values for the following parameters. You must provide these parameter values to the other CloudFormation templates that you run to create your cluster:

    VpcId

    The ID of your VPC.

    PublicSubnetIds

    The IDs of the new public subnets.

    PrivateSubnetIds

    The IDs of the new private subnets.

4.3.4.1. CloudFormation template for the VPC

The VPC CloudFormation template creates the Amazon Web Services (AWS) networking infrastructure, including the public and private subnets, that your OpenShift Container Platform cluster requires.

CloudFormation template for the VPC

AWSTemplateFormatVersion: 2010-09-09
Description: Template for Best Practice VPC with 1-3 AZs

Parameters:
  VpcCidr:
    AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-4]))$
    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-24.
    Default: 10.0.0.0/16
    Description: CIDR block for VPC.
    Type: String
  AvailabilityZoneCount:
    ConstraintDescription: "The number of availability zones. (Min: 1, Max: 3)"
    MinValue: 1
    MaxValue: 3
    Default: 1
    Description: "How many AZs to create VPC subnets for. (Min: 1, Max: 3)"
    Type: Number
  SubnetBits:
    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/19-27.
    MinValue: 5
    MaxValue: 13
    Default: 12
    Description: "Size of each subnet to create within the availability zones. (Min: 5 = /27, Max: 13 = /19)"
    Type: Number

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
    - Label:
        default: "Network Configuration"
      Parameters:
      - VpcCidr
      - SubnetBits
    - Label:
        default: "Availability Zones"
      Parameters:
      - AvailabilityZoneCount
    ParameterLabels:
      AvailabilityZoneCount:
        default: "Availability Zone Count"
      VpcCidr:
        default: "VPC CIDR"
      SubnetBits:
        default: "Bits Per Subnet"

Conditions:
  DoAz3: !Equals [3, !Ref AvailabilityZoneCount]
  DoAz2: !Or [!Equals [2, !Ref AvailabilityZoneCount], Condition: DoAz3]

Resources:
  VPC:
    Type: "AWS::EC2::VPC"
    Properties:
      EnableDnsSupport: "true"
      EnableDnsHostnames: "true"
      CidrBlock: !Ref VpcCidr
  PublicSubnet:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Select [0, !Cidr [!Ref VpcCidr, 6, !Ref SubnetBits]]
      AvailabilityZone: !Select
      - 0
      - Fn::GetAZs: !Ref "AWS::Region"
  PublicSubnet2:
    Type: "AWS::EC2::Subnet"
    Condition: DoAz2
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Select [1, !Cidr [!Ref VpcCidr, 6, !Ref SubnetBits]]
      AvailabilityZone: !Select
      - 1
      - Fn::GetAZs: !Ref "AWS::Region"
  PublicSubnet3:
    Type: "AWS::EC2::Subnet"
    Condition: DoAz3
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Select [2, !Cidr [!Ref VpcCidr, 6, !Ref SubnetBits]]
      AvailabilityZone: !Select
      - 2
      - Fn::GetAZs: !Ref "AWS::Region"
  InternetGateway:
    Type: "AWS::EC2::InternetGateway"
  GatewayToInternet:
    Type: "AWS::EC2::VPCGatewayAttachment"
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway
  PublicRouteTable:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: !Ref VPC
  PublicRoute:
    Type: "AWS::EC2::Route"
    DependsOn: GatewayToInternet
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway
  PublicSubnetRouteTableAssociation:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicRouteTable
  PublicSubnetRouteTableAssociation2:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Condition: DoAz2
    Properties:
      SubnetId: !Ref PublicSubnet2
      RouteTableId: !Ref PublicRouteTable
  PublicSubnetRouteTableAssociation3:
    Condition: DoAz3
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId: !Ref PublicSubnet3
      RouteTableId: !Ref PublicRouteTable
  PrivateSubnet:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Select [3, !Cidr [!Ref VpcCidr, 6, !Ref SubnetBits]]
      AvailabilityZone: !Select
      - 0
      - Fn::GetAZs: !Ref "AWS::Region"
  PrivateRouteTable:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: !Ref VPC
  PrivateSubnetRouteTableAssociation:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId: !Ref PrivateSubnet
      RouteTableId: !Ref PrivateRouteTable
  NAT:
    DependsOn:
    - GatewayToInternet
    Type: "AWS::EC2::NatGateway"
    Properties:
      AllocationId:
        "Fn::GetAtt":
        - EIP
        - AllocationId
      SubnetId: !Ref PublicSubnet
  EIP:
    Type: "AWS::EC2::EIP"
    Properties:
      Domain: vpc
  Route:
    Type: "AWS::EC2::Route"
    Properties:
      RouteTableId:
        Ref: PrivateRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId:
        Ref: NAT
  PrivateSubnet2:
    Type: "AWS::EC2::Subnet"
    Condition: DoAz2
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Select [4, !Cidr [!Ref VpcCidr, 6, !Ref SubnetBits]]
      AvailabilityZone: !Select
      - 1
      - Fn::GetAZs: !Ref "AWS::Region"
  PrivateRouteTable2:
    Type: "AWS::EC2::RouteTable"
    Condition: DoAz2
    Properties:
      VpcId: !Ref VPC
  PrivateSubnetRouteTableAssociation2:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Condition: DoAz2
    Properties:
      SubnetId: !Ref PrivateSubnet2
      RouteTableId: !Ref PrivateRouteTable2
  NAT2:
    DependsOn:
    - GatewayToInternet
    Type: "AWS::EC2::NatGateway"
    Condition: DoAz2
    Properties:
      AllocationId:
        "Fn::GetAtt":
        - EIP2
        - AllocationId
      SubnetId: !Ref PublicSubnet2
  EIP2:
    Type: "AWS::EC2::EIP"
    Condition: DoAz2
    Properties:
      Domain: vpc
  Route2:
    Type: "AWS::EC2::Route"
    Condition: DoAz2
    Properties:
      RouteTableId:
        Ref: PrivateRouteTable2
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId:
        Ref: NAT2
  PrivateSubnet3:
    Type: "AWS::EC2::Subnet"
    Condition: DoAz3
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Select [5, !Cidr [!Ref VpcCidr, 6, !Ref SubnetBits]]
      AvailabilityZone: !Select
      - 2
      - Fn::GetAZs: !Ref "AWS::Region"
  PrivateRouteTable3:
    Type: "AWS::EC2::RouteTable"
    Condition: DoAz3
    Properties:
      VpcId: !Ref VPC
  PrivateSubnetRouteTableAssociation3:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Condition: DoAz3
    Properties:
      SubnetId: !Ref PrivateSubnet3
      RouteTableId: !Ref PrivateRouteTable3
  NAT3:
    DependsOn:
    - GatewayToInternet
    Type: "AWS::EC2::NatGateway"
    Condition: DoAz3
    Properties:
      AllocationId:
        "Fn::GetAtt":
        - EIP3
        - AllocationId
      SubnetId: !Ref PublicSubnet3
  EIP3:
    Type: "AWS::EC2::EIP"
    Condition: DoAz3
    Properties:
      Domain: vpc
  Route3:
    Type: "AWS::EC2::Route"
    Condition: DoAz3
    Properties:
      RouteTableId:
        Ref: PrivateRouteTable3
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId:
        Ref: NAT3
  S3Endpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Principal: '*'
          Action:
          - '*'
          Resource:
          - '*'
      RouteTableIds:
      - !Ref PublicRouteTable
      - !Ref PrivateRouteTable
      - !If [DoAz2, !Ref PrivateRouteTable2, !Ref "AWS::NoValue"]
      - !If [DoAz3, !Ref PrivateRouteTable3, !Ref "AWS::NoValue"]
      ServiceName: !Join
      - ''
      - - com.amazonaws.
        - !Ref 'AWS::Region'
        - .s3
      VpcId: !Ref VPC

Outputs:
  VpcId:
    Description: ID of the new VPC.
    Value: !Ref VPC
  PublicSubnetIds:
    Description: Subnet IDs of the public subnets.
    Value:
      !Join [
        ",",
        [!Ref PublicSubnet, !If [DoAz2, !Ref PublicSubnet2, !Ref "AWS::NoValue"], !If [DoAz3, !Ref PublicSubnet3, !Ref "AWS::NoValue"]]
      ]
  PrivateSubnetIds:
    Description: Subnet IDs of the private subnets.
    Value:
      !Join [
        ",",
        [!Ref PrivateSubnet, !If [DoAz2, !Ref PrivateSubnet2, !Ref "AWS::NoValue"], !If [DoAz3, !Ref PrivateSubnet3, !Ref "AWS::NoValue"]]
      ]
  PublicRouteTableId:
    Description: Public Route table ID
    Value: !Ref PublicRouteTable
  PrivateRouteTableIds:
    Description: Private Route table IDs
    Value:
      !Join [
        ",",
        [
          !Join ["=", [
            !Select [0, "Fn::GetAZs": !Ref "AWS::Region"],
            !Ref PrivateRouteTable
          ]],
          !If [DoAz2,
               !Join ["=", [!Select [1, "Fn::GetAZs": !Ref "AWS::Region"], !Ref PrivateRouteTable2]],
               !Ref "AWS::NoValue"
          ],
          !If [DoAz3,
               !Join ["=", [!Select [2, "Fn::GetAZs": !Ref "AWS::Region"], !Ref PrivateRouteTable3]],
               !Ref "AWS::NoValue"
          ]
        ]
      ]

4.3.5. Creating networking and load balancing components in AWS

To route traffic to your OpenShift Container Platform cluster, configure the networking and load balancing components in Amazon Web Services (AWS) by using the provided CloudFormation template.

You can use the provided CloudFormation template and a custom parameter file to create a stack of AWS resources. The stack represents the networking and load balancing components that your OpenShift Container Platform cluster requires. The template also creates a hosted zone and subnet tags.

You can run the template many times within a single Virtual Private Cloud (VPC).

Note

If you do not use the provided CloudFormation template to create your AWS infrastructure, you must review the provided information and manually create the infrastructure. If your cluster does not initialize correctly, you might have to contact Red Hat support with your installation logs.

Prerequisites

  • You created and configured a VPC and associated subnets in AWS.

Procedure

  1. Obtain the hosted zone ID for the Route 53 base domain that you specified in the install-config.yaml file for your cluster. You can obtain details about your hosted zone by running the following command:

    $ aws route53 list-hosted-zones-by-name --dns-name <route53_domain>

    where <route53_domain> is the Route 53 base domain that you used when you generated the install-config.yaml file for the cluster.

    Example output

    mycluster.example.com.	False	100
    HOSTEDZONES	65F8F38E-2268-B835-E15C-AB55336FCBFA	/hostedzone/Z21IXYZABCZ2A4	mycluster.example.com.	10

    In the example output, the hosted zone ID is Z21IXYZABCZ2A4.

  2. Create a JSON file that has the parameter values that the template requires:

    [
      {
        "ParameterKey": "ClusterName",
        "ParameterValue": "mycluster"
      },
      {
        "ParameterKey": "InfrastructureName",
        "ParameterValue": "mycluster-<random_string>"
      },
      {
        "ParameterKey": "HostedZoneId",
        "ParameterValue": "<random_string>"
      },
      {
        "ParameterKey": "HostedZoneName",
        "ParameterValue": "example.com"
      },
      {
        "ParameterKey": "PublicSubnets",
        "ParameterValue": "subnet-<random_string>"
      },
      {
        "ParameterKey": "PrivateSubnets",
        "ParameterValue": "subnet-<random_string>"
      },
      {
        "ParameterKey": "VpcId",
        "ParameterValue": "vpc-<random_string>"
      }
    ]

    where:

    ClusterName
    Specifies a short, representative cluster name to use for hostnames, and so on. Set the value to the cluster name that you used when you generated the install-config.yaml file for the cluster.
    InfrastructureName
    Specifies the name for your cluster infrastructure that your Ignition config files encode for the cluster. Set the value to the infrastructure name that you extracted from the Ignition config file metadata, which has the format <cluster_name>-<random_string>.
    HostedZoneId
    Specifies the Route 53 public zone ID to register the targets with. Set the value to the Route 53 public zone ID, which has a format similar to Z21IXYZABCZ2A4. You can obtain this value from the AWS console.
    HostedZoneName
    Specifies the Route 53 zone to register the targets with. Set the value to the Route 53 base domain that you used when you generated the install-config.yaml file for the cluster. Do not include the trailing period (.) that is displayed in the AWS console.
    PublicSubnets
    Specifies the public subnets that you created for your VPC. Set the value to the PublicSubnetIds value from the output of the CloudFormation template for the VPC.
    PrivateSubnets
    Specifies the private subnets that you created for your VPC. Set the value to the PrivateSubnetIds value from the output of the CloudFormation template for the VPC.
    VpcId
    Specifies the VPC that you created for the cluster. Set the value to the VpcId value from the output of the CloudFormation template for the VPC.
  3. Copy the template from the CloudFormation template for the network and load balancers section and save it as a YAML file on your computer. This template describes the networking and load balancing objects that your cluster requires.

    Important

    If you are deploying your cluster to an AWS government or secret region, you must update the InternalApiServerRecord in the CloudFormation template to use CNAME records. Records of type ALIAS are not supported for AWS government regions.

  4. Launch the CloudFormation template to create a stack of AWS resources for the networking and load balancing components:

    Important

    You must enter the command on a single line.

    $ aws cloudformation create-stack --stack-name <name> \
         --template-body file://<template>.yaml \
         --parameters file://<parameters>.json \
         --capabilities CAPABILITY_NAMED_IAM

    where:

    <name>
    Specifies the name for the CloudFormation stack, such as cluster-dns. You need the name of this stack if you remove the cluster.
    <template>
    Specifies the relative path to and name of the CloudFormation template YAML file that you saved.
    <parameters>
    Specifies the relative path to and name of the CloudFormation parameters JSON file.
    CAPABILITY_NAMED_IAM
    You must explicitly declare this capability because the provided template creates some AWS::IAM::Role resources.

    Example output

    arn:aws:cloudformation:us-east-1:269333783861:stack/cluster-dns/cd3e5de0-2fd4-11eb-5cf0-12be5c33a183

  5. Confirm that the template components exist:

    $ aws cloudformation describe-stacks --stack-name <name>

    After the StackStatus displays CREATE_COMPLETE, the output displays values for the following parameters. You must give these parameter values to the other CloudFormation templates that you run to create your cluster:

    PrivateHostedZoneId

    Hosted zone ID for the private DNS.

    ExternalApiLoadBalancerName

    Full name of the external API load balancer.

    InternalApiLoadBalancerName

    Full name of the internal API load balancer.

    ApiServerDnsName

    Full hostname of the API server.

    RegisterNlbIpTargetsLambda

    Lambda ARN useful to help register and unregister IP targets for these load balancers.

    ExternalApiTargetGroupArn

    ARN of external API target group.

    InternalApiTargetGroupArn

    ARN of internal API target group.

    InternalServiceTargetGroupArn

    ARN of internal service target group.

4.3.5.1. CloudFormation template for the network and load balancers

The networking CloudFormation template creates the Route 53 DNS entries and load balancers on Amazon Web Services (AWS) that route traffic to your OpenShift Container Platform control plane and applications.

CloudFormation template for the network and load balancers

AWSTemplateFormatVersion: 2010-09-09
Description: Template for OpenShift Cluster Network Elements (Route53 & LBs)

Parameters:
  ClusterName:
    AllowedPattern: ^([a-zA-Z][a-zA-Z0-9\-]{0,26})$
    MaxLength: 27
    MinLength: 1
    ConstraintDescription: Cluster name must be alphanumeric, start with a letter, and have a maximum of 27 characters.
    Description: A short, representative cluster name to use for host names and other identifying names.
    Type: String
  InfrastructureName:
    AllowedPattern: ^([a-zA-Z][a-zA-Z0-9\-]{0,26})$
    MaxLength: 27
    MinLength: 1
    ConstraintDescription: Infrastructure name must be alphanumeric, start with a letter, and have a maximum of 27 characters.
    Description: A short, unique cluster ID used to tag cloud resources and identify items owned or used by the cluster.
    Type: String
  HostedZoneId:
    Description: The Route53 public zone ID to register the targets with, such as Z21IXYZABCZ2A4.
    Type: String
  HostedZoneName:
    Description: The Route53 zone to register the targets with, such as example.com. Omit the trailing period.
    Type: String
    Default: "example.com"
  PublicSubnets:
    Description: The internet-facing subnets.
    Type: List<AWS::EC2::Subnet::Id>
  PrivateSubnets:
    Description: The internal subnets.
    Type: List<AWS::EC2::Subnet::Id>
  VpcId:
    Description: The VPC-scoped resources will belong to this VPC.
    Type: AWS::EC2::VPC::Id

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
    - Label:
        default: "Cluster Information"
      Parameters:
      - ClusterName
      - InfrastructureName
    - Label:
        default: "Network Configuration"
      Parameters:
      - VpcId
      - PublicSubnets
      - PrivateSubnets
    - Label:
        default: "DNS"
      Parameters:
      - HostedZoneName
      - HostedZoneId
    ParameterLabels:
      ClusterName:
        default: "Cluster Name"
      InfrastructureName:
        default: "Infrastructure Name"
      VpcId:
        default: "VPC ID"
      PublicSubnets:
        default: "Public Subnets"
      PrivateSubnets:
        default: "Private Subnets"
      HostedZoneName:
        default: "Public Hosted Zone Name"
      HostedZoneId:
        default: "Public Hosted Zone ID"

Resources:
  ExtApiElb:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: !Join ["-", [!Ref InfrastructureName, "ext"]]
      IpAddressType: ipv4
      Subnets: !Ref PublicSubnets
      Type: network

  IntApiElb:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: !Join ["-", [!Ref InfrastructureName, "int"]]
      Scheme: internal
      IpAddressType: ipv4
      Subnets: !Ref PrivateSubnets
      Type: network

  IntDns:
    Type: "AWS::Route53::HostedZone"
    Properties:
      HostedZoneConfig:
        Comment: "Managed by CloudFormation"
      Name: !Join [".", [!Ref ClusterName, !Ref HostedZoneName]]
      HostedZoneTags:
      - Key: Name
        Value: !Join ["-", [!Ref InfrastructureName, "int"]]
      - Key: !Join ["", ["kubernetes.io/cluster/", !Ref InfrastructureName]]
        Value: "owned"
      VPCs:
      - VPCId: !Ref VpcId
        VPCRegion: !Ref "AWS::Region"

  ExternalApiServerRecord:
    Type: AWS::Route53::RecordSetGroup
    Properties:
      Comment: Alias record for the API server
      HostedZoneId: !Ref HostedZoneId
      RecordSets:
      - Name:
          !Join [
            ".",
            ["api", !Ref ClusterName, !Join ["", [!Ref HostedZoneName, "."]]],
          ]
        Type: A
        AliasTarget:
          HostedZoneId: !GetAtt ExtApiElb.CanonicalHostedZoneID
          DNSName: !GetAtt ExtApiElb.DNSName

  InternalApiServerRecord:
    Type: AWS::Route53::RecordSetGroup
    Properties:
      Comment: Alias record for the API server
      HostedZoneId: !Ref IntDns
      RecordSets:
      - Name:
          !Join [
            ".",
            ["api", !Ref ClusterName, !Join ["", [!Ref HostedZoneName, "."]]],
          ]
        Type: A
        AliasTarget:
          HostedZoneId: !GetAtt IntApiElb.CanonicalHostedZoneID
          DNSName: !GetAtt IntApiElb.DNSName
      - Name:
          !Join [
            ".",
            ["api-int", !Ref ClusterName, !Join ["", [!Ref HostedZoneName, "."]]],
          ]
        Type: A
        AliasTarget:
          HostedZoneId: !GetAtt IntApiElb.CanonicalHostedZoneID
          DNSName: !GetAtt IntApiElb.DNSName

  ExternalApiListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
      - Type: forward
        TargetGroupArn:
          Ref: ExternalApiTargetGroup
      LoadBalancerArn:
        Ref: ExtApiElb
      Port: 6443
      Protocol: TCP

  ExternalApiTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckIntervalSeconds: 10
      HealthCheckPath: "/readyz"
      HealthCheckPort: 6443
      HealthCheckProtocol: HTTPS
      HealthyThresholdCount: 2
      UnhealthyThresholdCount: 2
      Port: 6443
      Protocol: TCP
      TargetType: ip
      VpcId:
        Ref: VpcId
      TargetGroupAttributes:
      - Key: deregistration_delay.timeout_seconds
        Value: 60

  InternalApiListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
      - Type: forward
        TargetGroupArn:
          Ref: InternalApiTargetGroup
      LoadBalancerArn:
        Ref: IntApiElb
      Port: 6443
      Protocol: TCP

  InternalApiTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckIntervalSeconds: 10
      HealthCheckPath: "/readyz"
      HealthCheckPort: 6443
      HealthCheckProtocol: HTTPS
      HealthyThresholdCount: 2
      UnhealthyThresholdCount: 2
      Port: 6443
      Protocol: TCP
      TargetType: ip
      VpcId:
        Ref: VpcId
      TargetGroupAttributes:
      - Key: deregistration_delay.timeout_seconds
        Value: 60

  InternalServiceInternalListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
      - Type: forward
        TargetGroupArn:
          Ref: InternalServiceTargetGroup
      LoadBalancerArn:
        Ref: IntApiElb
      Port: 22623
      Protocol: TCP

  InternalServiceTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckIntervalSeconds: 10
      HealthCheckPath: "/healthz"
      HealthCheckPort: 22623
      HealthCheckProtocol: HTTPS
      HealthyThresholdCount: 2
      UnhealthyThresholdCount: 2
      Port: 22623
      Protocol: TCP
      TargetType: ip
      VpcId:
        Ref: VpcId
      TargetGroupAttributes:
      - Key: deregistration_delay.timeout_seconds
        Value: 60

  RegisterTargetLambdaIamRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Join ["-", [!Ref InfrastructureName, "nlb", "lambda", "role"]]
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
        - Effect: "Allow"
          Principal:
            Service:
            - "lambda.amazonaws.com"
          Action:
          - "sts:AssumeRole"
      Path: "/"
      Policies:
      - PolicyName: !Join ["-", [!Ref InfrastructureName, "master", "policy"]]
        PolicyDocument:
          Version: "2012-10-17"
          Statement:
          - Effect: "Allow"
            Action:
              [
                "elasticloadbalancing:RegisterTargets",
                "elasticloadbalancing:DeregisterTargets",
              ]
            Resource: !Ref InternalApiTargetGroup
          - Effect: "Allow"
            Action:
              [
                "elasticloadbalancing:RegisterTargets",
                "elasticloadbalancing:DeregisterTargets",
              ]
            Resource: !Ref InternalServiceTargetGroup
          - Effect: "Allow"
            Action:
              [
                "elasticloadbalancing:RegisterTargets",
                "elasticloadbalancing:DeregisterTargets",
              ]
            Resource: !Ref ExternalApiTargetGroup

  RegisterNlbIpTargets:
    Type: "AWS::Lambda::Function"
    Properties:
      Handler: "index.handler"
      Role:
        Fn::GetAtt:
        - "RegisterTargetLambdaIamRole"
        - "Arn"
      Code:
        ZipFile: |
          import json
          import boto3
          import cfnresponse
          def handler(event, context):
            elb = boto3.client('elbv2')
            if event['RequestType'] == 'Delete':
              elb.deregister_targets(TargetGroupArn=event['ResourceProperties']['TargetArn'],Targets=[{'Id': event['ResourceProperties']['TargetIp']}])
            elif event['RequestType'] == 'Create':
              elb.register_targets(TargetGroupArn=event['ResourceProperties']['TargetArn'],Targets=[{'Id': event['ResourceProperties']['TargetIp']}])
            responseData = {}
            cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, event['ResourceProperties']['TargetArn']+event['ResourceProperties']['TargetIp'])
      Runtime: "python3.11"
      Timeout: 120

  RegisterSubnetTagsLambdaIamRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Join ["-", [!Ref InfrastructureName, "subnet-tags-lambda-role"]]
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
        - Effect: "Allow"
          Principal:
            Service:
            - "lambda.amazonaws.com"
          Action:
          - "sts:AssumeRole"
      Path: "/"
      Policies:
      - PolicyName: !Join ["-", [!Ref InfrastructureName, "subnet-tagging-policy"]]
        PolicyDocument:
          Version: "2012-10-17"
          Statement:
          - Effect: "Allow"
            Action:
              [
                "ec2:DeleteTags",
                "ec2:CreateTags"
              ]
            Resource: "arn:aws:ec2:*:*:subnet/*"
          - Effect: "Allow"
            Action:
              [
                "ec2:DescribeSubnets",
                "ec2:DescribeTags"
              ]
            Resource: "*"

  RegisterSubnetTags:
    Type: "AWS::Lambda::Function"
    Properties:
      Handler: "index.handler"
      Role:
        Fn::GetAtt:
        - "RegisterSubnetTagsLambdaIamRole"
        - "Arn"
      Code:
        ZipFile: |
          import json
          import boto3
          import cfnresponse
          def handler(event, context):
            ec2_client = boto3.client('ec2')
            if event['RequestType'] == 'Delete':
              for subnet_id in event['ResourceProperties']['Subnets']:
                ec2_client.delete_tags(Resources=[subnet_id], Tags=[{'Key': 'kubernetes.io/cluster/' + event['ResourceProperties']['InfrastructureName']}]);
            elif event['RequestType'] == 'Create':
              for subnet_id in event['ResourceProperties']['Subnets']:
                ec2_client.create_tags(Resources=[subnet_id], Tags=[{'Key': 'kubernetes.io/cluster/' + event['ResourceProperties']['InfrastructureName'], 'Value': 'shared'}]);
            responseData = {}
            cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, event['ResourceProperties']['InfrastructureName']+event['ResourceProperties']['Subnets'][0])
      Runtime: "python3.11"
      Timeout: 120

  RegisterPublicSubnetTags:
    Type: Custom::SubnetRegister
    Properties:
      ServiceToken: !GetAtt RegisterSubnetTags.Arn
      InfrastructureName: !Ref InfrastructureName
      Subnets: !Ref PublicSubnets

  RegisterPrivateSubnetTags:
    Type: Custom::SubnetRegister
    Properties:
      ServiceToken: !GetAtt RegisterSubnetTags.Arn
      InfrastructureName: !Ref InfrastructureName
      Subnets: !Ref PrivateSubnets

Outputs:
  PrivateHostedZoneId:
    Description: Hosted zone ID for the private DNS, which is required for private records.
    Value: !Ref IntDns
  ExternalApiLoadBalancerName:
    Description: Full name of the external API load balancer.
    Value: !GetAtt ExtApiElb.LoadBalancerFullName
  InternalApiLoadBalancerName:
    Description: Full name of the internal API load balancer.
    Value: !GetAtt IntApiElb.LoadBalancerFullName
  ApiServerDnsName:
    Description: Full hostname of the API server, which is required for the Ignition config files.
    Value: !Join [".", ["api-int", !Ref ClusterName, !Ref HostedZoneName]]
  RegisterNlbIpTargetsLambda:
    Description: Lambda ARN useful to help register or deregister IP targets for these load balancers.
    Value: !GetAtt RegisterNlbIpTargets.Arn
  ExternalApiTargetGroupArn:
    Description: ARN of the external API target group.
    Value: !Ref ExternalApiTargetGroup
  InternalApiTargetGroupArn:
    Description: ARN of the internal API target group.
    Value: !Ref InternalApiTargetGroup
  InternalServiceTargetGroupArn:
    Description: ARN of the internal service target group.
    Value: !Ref InternalServiceTargetGroup

Important

If you are deploying your cluster to an AWS government or secret region, you must update the InternalApiServerRecord to use CNAME records. Records of type ALIAS are not supported for AWS government regions. For example:

Type: CNAME
TTL: 10
ResourceRecords:
- !GetAtt IntApiElb.DNSName

4.3.6. Creating security group and roles in AWS

To control access to your OpenShift Container Platform cluster resources, create the required security groups and IAM roles in Amazon Web Services (AWS) by using the provided CloudFormation template.

You can use the provided CloudFormation template and a custom parameter file to create a stack of AWS resources. The stack represents the security groups and roles that your OpenShift Container Platform cluster requires.

Note

If you do not use the provided CloudFormation template to create your AWS infrastructure, you must review the provided information and manually create the infrastructure. If your cluster does not initialize correctly, you might have to contact Red Hat support with your installation logs.

Procedure

  1. Create a JSON file that has the parameter values that the template requires:

    [
      {
        "ParameterKey": "InfrastructureName",
        "ParameterValue": "mycluster-<random_string>"
      },
      {
        "ParameterKey": "VpcCidr",
        "ParameterValue": "10.0.0.0/16"
      },
      {
        "ParameterKey": "PrivateSubnets",
        "ParameterValue": "subnet-<random_string>"
      },
      {
        "ParameterKey": "VpcId",
        "ParameterValue": "vpc-<random_string>"
      }
    ]

    where:

    InfrastructureName
    Specifies the name for your cluster infrastructure that your Ignition config files encode for the cluster. Set the value to the infrastructure name that you extracted from the Ignition config file metadata, which has the format <cluster_name>-<random_string>.
    VpcCidr
    Specifies the CIDR block for the VPC. Set the value to the CIDR block parameter that you used for the VPC that you defined in the form x.x.x.x/16-24.
    PrivateSubnets
    Specifies the private subnets that you created for your VPC. Set the value to the PrivateSubnetIds value from the output of the CloudFormation template for the VPC.
    VpcId
    Specifies the VPC that you created for the cluster. Set the value to the VpcId value from the output of the CloudFormation template for the VPC.
  2. Copy the template from the CloudFormation template for security objects section and save it as a YAML file on your computer. This template describes the security groups and roles that your cluster requires.
  3. Launch the CloudFormation template to create a stack of AWS resources that represent the security groups and roles:

    Important

    You must enter the command on a single line.

    $ aws cloudformation create-stack --stack-name <name> \
         --template-body file://<template>.yaml \
         --parameters file://<parameters>.json \
         --capabilities CAPABILITY_NAMED_IAM

    where:

    <name>
    Specifies the name for the CloudFormation stack, such as cluster-sec. You need the name of this stack if you remove the cluster.
    <template>
    Specifies the relative path to and name of the CloudFormation template YAML file that you saved.
    <parameters>
    Specifies the relative path to and name of the CloudFormation parameters JSON file.
    CAPABILITY_NAMED_IAM
    You must explicitly declare this capability because the provided template creates some AWS::IAM::Role and AWS::IAM::InstanceProfile resources.

    Example output

    arn:aws:cloudformation:us-east-1:269333783861:stack/cluster-sec/03bd4210-2ed7-11eb-6d7a-13fc0b61e9db

  4. Confirm that the template components exist:

    $ aws cloudformation describe-stacks --stack-name <name>

    After the StackStatus displays CREATE_COMPLETE, the output displays values for the following parameters. You must give these parameter values to the other CloudFormation templates that you run to create your cluster:

    MasterSecurityGroupId

    Control plane security group ID

    WorkerSecurityGroupId

    Worker security group ID

    MasterInstanceProfile

    Control plane IAM instance profile

    WorkerInstanceProfile

    Worker IAM instance profile

4.3.6.1. CloudFormation template for security objects

The security CloudFormation template creates the IAM roles and security groups on Amazon Web Services (AWS) that control access to your OpenShift Container Platform cluster resources.

CloudFormation template for security objects

AWSTemplateFormatVersion: 2010-09-09
Description: Template for OpenShift Cluster Security Elements (Security Groups & IAM)

Parameters:
  InfrastructureName:
    AllowedPattern: ^([a-zA-Z][a-zA-Z0-9\-]{0,26})$
    MaxLength: 27
    MinLength: 1
    ConstraintDescription: Infrastructure name must be alphanumeric, start with a letter, and have a maximum of 27 characters.
    Description: A short, unique cluster ID used to tag cloud resources and identify items owned or used by the cluster.
    Type: String
  VpcCidr:
    AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-4]))$
    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-24.
    Default: 10.0.0.0/16
    Description: CIDR block for VPC.
    Type: String
  VpcId:
    Description: The VPC-scoped resources will belong to this VPC.
    Type: AWS::EC2::VPC::Id
  PrivateSubnets:
    Description: The internal subnets.
    Type: List<AWS::EC2::Subnet::Id>

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
    - Label:
        default: "Cluster Information"
      Parameters:
      - InfrastructureName
    - Label:
        default: "Network Configuration"
      Parameters:
      - VpcId
      - VpcCidr
      - PrivateSubnets
    ParameterLabels:
      InfrastructureName:
        default: "Infrastructure Name"
      VpcId:
        default: "VPC ID"
      VpcCidr:
        default: "VPC CIDR"
      PrivateSubnets:
        default: "Private Subnets"

Resources:
  MasterSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Cluster Master Security Group
      SecurityGroupIngress:
      - IpProtocol: icmp
        FromPort: 0
        ToPort: 0
        CidrIp: !Ref VpcCidr
      - IpProtocol: tcp
        FromPort: 22
        ToPort: 22
        CidrIp: !Ref VpcCidr
      - IpProtocol: tcp
        ToPort: 6443
        FromPort: 6443
        CidrIp: !Ref VpcCidr
      - IpProtocol: tcp
        FromPort: 22623
        ToPort: 22623
        CidrIp: !Ref VpcCidr
      VpcId: !Ref VpcId

  WorkerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Cluster Worker Security Group
      SecurityGroupIngress:
      - IpProtocol: icmp
        FromPort: 0
        ToPort: 0
        CidrIp: !Ref VpcCidr
      - IpProtocol: tcp
        FromPort: 22
        ToPort: 22
        CidrIp: !Ref VpcCidr
      VpcId: !Ref VpcId

  MasterIngressEtcd:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: etcd
      FromPort: 2379
      ToPort: 2380
      IpProtocol: tcp

  MasterIngressVxlan:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Vxlan packets
      FromPort: 4789
      ToPort: 4789
      IpProtocol: udp

  MasterIngressWorkerVxlan:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Vxlan packets
      FromPort: 4789
      ToPort: 4789
      IpProtocol: udp

  MasterIngressGeneve:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Geneve packets
      FromPort: 6081
      ToPort: 6081
      IpProtocol: udp

  MasterIngressWorkerGeneve:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Geneve packets
      FromPort: 6081
      ToPort: 6081
      IpProtocol: udp

  MasterIngressIpsecIke:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: IPsec IKE packets
      FromPort: 500
      ToPort: 500
      IpProtocol: udp

  MasterIngressIpsecNat:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: IPsec NAT-T packets
      FromPort: 4500
      ToPort: 4500
      IpProtocol: udp

  MasterIngressIpsecEsp:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: IPsec ESP packets
      IpProtocol: 50

  MasterIngressWorkerIpsecIke:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: IPsec IKE packets
      FromPort: 500
      ToPort: 500
      IpProtocol: udp

  MasterIngressWorkerIpsecNat:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: IPsec NAT-T packets
      FromPort: 4500
      ToPort: 4500
      IpProtocol: udp

  MasterIngressWorkerIpsecEsp:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: IPsec ESP packets
      IpProtocol: 50

  MasterIngressInternal:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Internal cluster communication
      FromPort: 9000
      ToPort: 9999
      IpProtocol: tcp

  MasterIngressWorkerInternal:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Internal cluster communication
      FromPort: 9000
      ToPort: 9999
      IpProtocol: tcp

  MasterIngressInternalUDP:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Internal cluster communication
      FromPort: 9000
      ToPort: 9999
      IpProtocol: udp

  MasterIngressWorkerInternalUDP:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Internal cluster communication
      FromPort: 9000
      ToPort: 9999
      IpProtocol: udp

  MasterIngressKube:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Kubernetes kubelet, scheduler and controller manager
      FromPort: 10250
      ToPort: 10259
      IpProtocol: tcp

  MasterIngressWorkerKube:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Kubernetes kubelet, scheduler and controller manager
      FromPort: 10250
      ToPort: 10259
      IpProtocol: tcp

  MasterIngressIngressServices:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Kubernetes ingress services
      FromPort: 30000
      ToPort: 32767
      IpProtocol: tcp

  MasterIngressWorkerIngressServices:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Kubernetes ingress services
      FromPort: 30000
      ToPort: 32767
      IpProtocol: tcp

  MasterIngressIngressServicesUDP:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Kubernetes ingress services
      FromPort: 30000
      ToPort: 32767
      IpProtocol: udp

  MasterIngressWorkerIngressServicesUDP:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Kubernetes ingress services
      FromPort: 30000
      ToPort: 32767
      IpProtocol: udp

  WorkerIngressVxlan:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Vxlan packets
      FromPort: 4789
      ToPort: 4789
      IpProtocol: udp

  WorkerIngressMasterVxlan:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Vxlan packets
      FromPort: 4789
      ToPort: 4789
      IpProtocol: udp

  WorkerIngressGeneve:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Geneve packets
      FromPort: 6081
      ToPort: 6081
      IpProtocol: udp

  WorkerIngressMasterGeneve:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Geneve packets
      FromPort: 6081
      ToPort: 6081
      IpProtocol: udp

  WorkerIngressIpsecIke:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: IPsec IKE packets
      FromPort: 500
      ToPort: 500
      IpProtocol: udp

  WorkerIngressIpsecNat:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: IPsec NAT-T packets
      FromPort: 4500
      ToPort: 4500
      IpProtocol: udp

  WorkerIngressIpsecEsp:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: IPsec ESP packets
      IpProtocol: 50

  WorkerIngressMasterIpsecIke:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: IPsec IKE packets
      FromPort: 500
      ToPort: 500
      IpProtocol: udp

  WorkerIngressMasterIpsecNat:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: IPsec NAT-T packets
      FromPort: 4500
      ToPort: 4500
      IpProtocol: udp

  WorkerIngressMasterIpsecEsp:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: IPsec ESP packets
      IpProtocol: 50

  WorkerIngressInternal:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Internal cluster communication
      FromPort: 9000
      ToPort: 9999
      IpProtocol: tcp

  WorkerIngressMasterInternal:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Internal cluster communication
      FromPort: 9000
      ToPort: 9999
      IpProtocol: tcp

  WorkerIngressInternalUDP:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Internal cluster communication
      FromPort: 9000
      ToPort: 9999
      IpProtocol: udp

  WorkerIngressMasterInternalUDP:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Internal cluster communication
      FromPort: 9000
      ToPort: 9999
      IpProtocol: udp

  WorkerIngressKube:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Kubernetes secure kubelet port
      FromPort: 10250
      ToPort: 10250
      IpProtocol: tcp

  WorkerIngressWorkerKube:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Internal Kubernetes communication
      FromPort: 10250
      ToPort: 10250
      IpProtocol: tcp

  WorkerIngressIngressServices:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Kubernetes ingress services
      FromPort: 30000
      ToPort: 32767
      IpProtocol: tcp

  WorkerIngressMasterIngressServices:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Kubernetes ingress services
      FromPort: 30000
      ToPort: 32767
      IpProtocol: tcp

  WorkerIngressIngressServicesUDP:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Kubernetes ingress services
      FromPort: 30000
      ToPort: 32767
      IpProtocol: udp

  WorkerIngressMasterIngressServicesUDP:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Kubernetes ingress services
      FromPort: 30000
      ToPort: 32767
      IpProtocol: udp

  MasterIamRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
        - Effect: "Allow"
          Principal:
            Service:
            - "ec2.amazonaws.com"
          Action:
          - "sts:AssumeRole"
      Policies:
      - PolicyName: !Join ["-", [!Ref InfrastructureName, "master", "policy"]]
        PolicyDocument:
          Version: "2012-10-17"
          Statement:
          - Effect: "Allow"
            Action:
            - "ec2:AttachVolume"
            - "ec2:AuthorizeSecurityGroupIngress"
            - "ec2:CreateSecurityGroup"
            - "ec2:CreateTags"
            - "ec2:CreateVolume"
            - "ec2:DeleteSecurityGroup"
            - "ec2:DeleteVolume"
            - "ec2:Describe*"
            - "ec2:DetachVolume"
            - "ec2:ModifyInstanceAttribute"
            - "ec2:ModifyVolume"
            - "ec2:RevokeSecurityGroupIngress"
            - "elasticloadbalancing:AddTags"
            - "elasticloadbalancing:AttachLoadBalancerToSubnets"
            - "elasticloadbalancing:ApplySecurityGroupsToLoadBalancer"
            - "elasticloadbalancing:CreateListener"
            - "elasticloadbalancing:CreateLoadBalancer"
            - "elasticloadbalancing:CreateLoadBalancerPolicy"
            - "elasticloadbalancing:CreateLoadBalancerListeners"
            - "elasticloadbalancing:CreateTargetGroup"
            - "elasticloadbalancing:ConfigureHealthCheck"
            - "elasticloadbalancing:DeleteListener"
            - "elasticloadbalancing:DeleteLoadBalancer"
            - "elasticloadbalancing:DeleteLoadBalancerListeners"
            - "elasticloadbalancing:DeleteTargetGroup"
            - "elasticloadbalancing:DeregisterInstancesFromLoadBalancer"
            - "elasticloadbalancing:DeregisterTargets"
            - "elasticloadbalancing:Describe*"
            - "elasticloadbalancing:DetachLoadBalancerFromSubnets"
            - "elasticloadbalancing:ModifyListener"
            - "elasticloadbalancing:ModifyLoadBalancerAttributes"
            - "elasticloadbalancing:ModifyTargetGroup"
            - "elasticloadbalancing:ModifyTargetGroupAttributes"
            - "elasticloadbalancing:RegisterInstancesWithLoadBalancer"
            - "elasticloadbalancing:RegisterTargets"
            - "elasticloadbalancing:SetLoadBalancerPoliciesForBackendServer"
            - "elasticloadbalancing:SetLoadBalancerPoliciesOfListener"
            - "kms:DescribeKey"
            Resource: "*"

  MasterInstanceProfile:
    Type: "AWS::IAM::InstanceProfile"
    Properties:
      Roles:
      - Ref: "MasterIamRole"

  WorkerIamRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
        - Effect: "Allow"
          Principal:
            Service:
            - "ec2.amazonaws.com"
          Action:
          - "sts:AssumeRole"
      Policies:
      - PolicyName: !Join ["-", [!Ref InfrastructureName, "worker", "policy"]]
        PolicyDocument:
          Version: "2012-10-17"
          Statement:
          - Effect: "Allow"
            Action:
            - "ec2:DescribeInstances"
            - "ec2:DescribeRegions"
            Resource: "*"

  WorkerInstanceProfile:
    Type: "AWS::IAM::InstanceProfile"
    Properties:
      Roles:
      - Ref: "WorkerIamRole"

Outputs:
  MasterSecurityGroupId:
    Description: Master Security Group ID
    Value: !GetAtt MasterSecurityGroup.GroupId

  WorkerSecurityGroupId:
    Description: Worker Security Group ID
    Value: !GetAtt WorkerSecurityGroup.GroupId

  MasterInstanceProfile:
    Description: Master IAM Instance Profile
    Value: !Ref MasterInstanceProfile

  WorkerInstanceProfile:
    Description: Worker IAM Instance Profile
    Value: !Ref WorkerInstanceProfile

4.3.7. Accessing RHCOS AMIs with stream metadata

To find the correct RHCOS boot image for your cluster, you can use stream metadata, which provides standardized information about RHCOS in the JSON format.

You can use the coreos print-stream-json subcommand of openshift-install to access information about the boot images in the stream metadata format. This command provides a method for printing stream metadata in a scriptable, machine-readable format.

For user-provisioned installations, the openshift-install binary has references to the version of RHCOS boot images that are tested for use with OpenShift Container Platform, such as the Amazon Web Services (AWS) AMI.

To parse the stream metadata, use one of the following methods:

Procedure

  • From a Go program, use the official stream-metadata-go library at https://github.com/coreos/stream-metadata-go. You can also view example code in the library.
  • From another programming language, such as Python or Ruby, use the JSON library of your preferred programming language.
  • From a command-line utility that handles JSON data, such as jq, print the current x86_64 or aarch64 AMI for an AWS region, such as us-west-1:

    For x86_64

    $ openshift-install coreos print-stream-json | jq -r '.architectures.x86_64.images.aws.regions["us-west-1"].image'

    Example output

    ami-0d3e625f84626bbda

    For aarch64

    $ openshift-install coreos print-stream-json | jq -r '.architectures.aarch64.images.aws.regions["us-west-1"].image'

    Example output

    ami-0af1d3b7fa5be2131

    The output of this command is the AWS AMI ID for your designated architecture and the us-west-1 region. The AMI must belong to the same region as the cluster.

4.3.8. RHCOS AMIs for the AWS infrastructure

To deploy OpenShift Container Platform nodes on Amazon Web Services (AWS), select from the valid Red Hat Enterprise Linux CoreOS (RHCOS) AMIs for your region and instance architecture.

Note

By importing your own AMI, you can also install to regions that do not have a published RHCOS AMI.

Table 4.9. x86_64 RHCOS AMIs
AWS zoneAWS AMI

af-south-1

ami-0a3b22174319ad66e

ap-east-1

ami-09cde51703738523d

ap-east-2

ami-05478426f756db81c

ap-northeast-1

ami-0d6f0c1a044b6848f

ap-northeast-2

ami-0d19d79e52ad365c8

ap-northeast-3

ami-0a0391de700b812ae

ap-south-1

ami-097ffb6f644b7bad1

ap-south-2

ami-08f1c0c6caafcf2c5

ap-southeast-1

ami-09b223a7c699ecde8

ap-southeast-2

ami-0a44bb6d4903a93a1

ap-southeast-3

ami-01469b817e364700f

ap-southeast-4

ami-086cc002b6d450301

ap-southeast-5

ami-0b5b9be3ea6fc17de

ap-southeast-6

ami-03a6ddee59246ab62

ap-southeast-7

ami-03ce4d4bb4f67e777

ca-central-1

ami-0b23054e68ef5ec3b

ca-west-1

ami-0541a60892c677593

eu-central-1

ami-006a33223c87af648

eu-central-2

ami-05ddf59e283155ea1

eu-north-1

ami-054f384036093db98

eu-south-1

ami-0a1cc6a65238669f3

eu-south-2

ami-0fe02b801fea5edf6

eu-west-1

ami-0632ffa330e30aea1

eu-west-2

ami-05829d8d5c031e4a8

eu-west-3

ami-00be64f508df27900

il-central-1

ami-0eeea15b1c070e051

me-central-1

ami-090084b481adf23e9

me-south-1

ami-0569abe19529c8b10

mx-central-1

ami-05ab0cf33b0e946a7

sa-east-1

ami-04dd4c56b43a23fb5

us-east-1

ami-04018496b0a1da2d2

us-east-2

ami-0b264801b0e00009c

us-gov-east-1

ami-042feba6717887157

us-gov-west-1

ami-0b05862564ac8353d

us-west-1

ami-08f548f5be577ce2d

us-west-2

ami-04941543f3e575579

Table 4.10. aarch64 RHCOS AMIs
AWS zoneAWS AMI

af-south-1

ami-0265ec024c31e7603

ap-east-1

ami-01d0891e1fa7c28fe

ap-east-2

ami-0de88496066d7428e

ap-northeast-1

ami-0d7c8859dc8f2ac02

ap-northeast-2

ami-00377959ff7cf0ed6

ap-northeast-3

ami-095386042a7673286

ap-south-1

ami-09f0f012b2c626f59

ap-south-2

ami-01c8221c9a56e0c74

ap-southeast-1

ami-0c27520bfa297e78a

ap-southeast-2

ami-0af72833671d615f1

ap-southeast-3

ami-085607af8f322e956

ap-southeast-4

ami-03d8bfd58de713367

ap-southeast-5

ami-0f6479fb82d8108d1

ap-southeast-6

ami-0a6a284e74f2e9afd

ap-southeast-7

ami-054eb3c4286f4dbca

ca-central-1

ami-032e08fde31f0a6cc

ca-west-1

ami-07d83e72beff3eb6c

eu-central-1

ami-0a62c879da82e8f99

eu-central-2

ami-09c91e670678ce2c1

eu-north-1

ami-0e896b8e4e7de42be

eu-south-1

ami-01718000bd7650956

eu-south-2

ami-02c48b6c8488542b2

eu-west-1

ami-06ea845fe728a8891

eu-west-2

ami-0e6c67a8674179e1b

eu-west-3

ami-0c4cb83cc7e4ec057

il-central-1

ami-00a88a6e634ac6676

me-central-1

ami-09aff5ac8bd25e9b8

me-south-1

ami-043e9d5894e68426d

mx-central-1

ami-00c0f1b2fc7ab92d4

sa-east-1

ami-0af3988f6b0fbee7f

us-east-1

ami-02ffd1d5ed7351ceb

us-east-2

ami-0d08ccc7bcf77433d

us-gov-east-1

ami-0b183fafd7eeae965

us-gov-west-1

ami-0411a4dd8cbf726db

us-west-1

ami-06149aec55f3e1d6c

us-west-2

ami-0c2bafedf2fc1dfc3

4.3.8.1. AWS regions without a published RHCOS AMI

You can deploy an OpenShift Container Platform cluster to Amazon Web Services (AWS) regions without native support for a Red Hat Enterprise Linux CoreOS (RHCOS) Amazon Machine Image (AMI) or the AWS software development kit (SDK).

If a published AMI is not available for an AWS region, you can upload a custom AMI before installing the cluster.

If you are deploying to a region not supported by the AWS SDK and you do not specify a custom AMI, the installation program copies the us-east-1 AMI to the user account automatically. Then the installation program creates the control plane machines with encrypted Elastic Block Store (EBS) volumes by using the default or user-specified Key Management Service (KMS) key. This allows the AMI to follow the same process workflow as published RHCOS AMIs.

A region without native support for an RHCOS AMI is not available to select from the terminal during cluster creation because it is not published. However, you can install to this region by configuring the custom AMI in the install-config.yaml file.

4.3.8.2. Uploading a custom RHCOS AMI in AWS

If you are deploying to a custom AWS region, you must upload a custom Red Hat Enterprise Linux CoreOS (RHCOS) Amazon Machine Image (AMI) that belongs to that region.

Prerequisites

  • You configured an AWS account.
  • You created an Amazon S3 bucket with the required IAM service role.
  • You uploaded your RHCOS VMDK file to Amazon S3. The RHCOS VMDK file must be the highest version that is less than or equal to the OpenShift Container Platform version you are installing.
  • You downloaded the AWS CLI and installed it on your computer. See Install the AWS CLI Using the Bundled Installer.

Procedure

  1. Export your AWS profile as an environment variable by running the following command:

    $ export AWS_PROFILE=<aws_profile>

    Replace <aws_profile> with the AWS profile name that holds your AWS credentials, such as govcloud or beijingadmin.

  2. Export the region to associate with your custom AMI as an environment variable by running the following command:

    $ export AWS_DEFAULT_REGION=<aws_region>

    Replace <aws_region> with the AWS region, such as us-gov-east-1 or cn-north-1.

  3. Export the version of RHCOS you uploaded to Amazon S3 as an environment variable by running the following command:

    $ export RHCOS_VERSION=<version>

    Replace <version> with the RHCOS VMDK version, such as 4.21.0.

  4. Export the Amazon S3 bucket name as an environment variable by running the following command:

    $ export VMIMPORT_BUCKET_NAME=<s3_bucket_name>
  5. Create the containers.json file and define your RHCOS VMDK file by running the following command:

    $ cat <<EOF > containers.json
    {
       "Description": "rhcos-${RHCOS_VERSION}-x86_64-aws.x86_64",
       "Format": "vmdk",
       "UserBucket": {
          "S3Bucket": "${VMIMPORT_BUCKET_NAME}",
          "S3Key": "rhcos-${RHCOS_VERSION}-x86_64-aws.x86_64.vmdk"
       }
    }
    EOF
  6. Import the RHCOS disk as an Amazon EBS snapshot by running the following command:

    $ aws ec2 import-snapshot --region ${AWS_DEFAULT_REGION} \
         --description "<description>" \
         --disk-container "file://<file_path>/containers.json"

    where:

    --description
    Specifies the description of your RHCOS disk being imported, like rhcos-${RHCOS_VERSION}-x86_64-aws.x86_64.
    --disk-container
    Specifies the file path to the JSON file describing your RHCOS disk. The JSON file should contain your Amazon S3 bucket name and key.
  7. Check the status of the image import by running the following command::

    $ watch -n 5 aws ec2 describe-import-snapshot-tasks --region ${AWS_DEFAULT_REGION}

    Example output

    {
        "ImportSnapshotTasks": [
            {
                "Description": "rhcos-4.7.0-x86_64-aws.x86_64",
                "ImportTaskId": "import-snap-fh6i8uil",
                "SnapshotTaskDetail": {
                    "Description": "rhcos-4.7.0-x86_64-aws.x86_64",
                    "DiskImageSize": 819056640.0,
                    "Format": "VMDK",
                    "SnapshotId": "snap-06331325870076318",
                    "Status": "completed",
                    "UserBucket": {
                        "S3Bucket": "external-images",
                        "S3Key": "rhcos-4.7.0-x86_64-aws.x86_64.vmdk"
                    }
                }
            }
        ]
    }

    Copy the SnapshotId to register the image.

  8. Create a custom RHCOS AMI from the RHCOS snapshot by running the following command:

    $ aws ec2 register-image \
       --region ${AWS_DEFAULT_REGION} \
       --architecture x86_64 \
       --description "rhcos-${RHCOS_VERSION}-x86_64-aws.x86_64" \
       --ena-support \
       --name "rhcos-${RHCOS_VERSION}-x86_64-aws.x86_64" \
       --virtualization-type hvm \
       --root-device-name '/dev/xvda' \
       --block-device-mappings 'DeviceName=/dev/xvda,Ebs={DeleteOnTermination=true,SnapshotId=<snapshot_ID>}'

    where:

    --architecture
    Specifies the RHCOS VMDK architecture type, such as x86_64, aarch64, s390x, or ppc64le.
    --description
    Specifies the Description from the imported snapshot.
    --name
    Specifies the name of the RHCOS AMI.
    --block-device-mappings
    Specifies the SnapshotID from the imported snapshot.

4.3.9. Creating the bootstrap node in AWS

To initialize the OpenShift Container Platform control plane, create the bootstrap node in Amazon Web Services (AWS) by uploading the Ignition config to an S3 bucket and launching the CloudFormation template.

  • Providing a location to serve the bootstrap.ign Ignition config file to your cluster. This file is in your installation directory. The provided CloudFormation template assumes that you serve the Ignition config files for your cluster from an S3 bucket. If you choose to serve the files from another location, you must change the templates.
  • Using the provided CloudFormation template and a custom parameter file to create a stack of AWS resources. The stack represents the bootstrap node that your OpenShift Container Platform installation requires.
Note

If you do not use the provided CloudFormation template to create your bootstrap node, you must review the provided information and manually create the infrastructure. If your cluster does not initialize correctly, you might have to contact Red Hat support with your installation logs.

Prerequisites

  • You created and configured DNS, load balancers, and listeners in AWS.
  • You created the security groups and roles required for your cluster in AWS.

Procedure

  1. Create the bucket by running the following command:

    $ aws s3 mb s3://<cluster_name>-infra

    where <cluster_name>-infra is the bucket name. When creating the install-config.yaml file, replace <cluster_name> with the name specified for the cluster.

    You must use a presigned URL for your S3 bucket, instead of the s3:// schema, if you are:

    • Deploying to a region that has endpoints that differ from the AWS SDK.
    • Deploying a proxy.
    • Providing your own custom endpoints.
  2. Upload the bootstrap.ign Ignition config file to the bucket by running the following command:

    $ aws s3 cp <installation_directory>/bootstrap.ign s3://<cluster_name>-infra/bootstrap.ign

    where <installation_directory> is the path to the directory that you stored the installation files in.

  3. Verify that the file uploaded by running the following command:

    $ aws s3 ls s3://<cluster_name>-infra/

    Example output

    2019-04-03 16:15:16     314878 bootstrap.ign

    Note

    The bootstrap Ignition config file does have secrets, such as X.509 keys. The following steps give basic security for the S3 bucket. To give additional security, you can enable an S3 bucket policy to allow only certain users, such as the OpenShift IAM user, to access objects that the bucket has. You can avoid S3 entirely and serve your bootstrap Ignition config file from any address that the bootstrap machine can reach.

  4. Create a JSON file that has the parameter values that the template requires:

    [
      {
        "ParameterKey": "InfrastructureName",
        "ParameterValue": "mycluster-<random_string>"
      },
      {
        "ParameterKey": "RhcosAmi",
        "ParameterValue": "ami-<random_string>"
      },
      {
        "ParameterKey": "AllowedBootstrapSshCidr",
        "ParameterValue": "0.0.0.0/0"
      },
      {
        "ParameterKey": "PublicSubnet",
        "ParameterValue": "subnet-<random_string>"
      },
      {
        "ParameterKey": "MasterSecurityGroupId",
        "ParameterValue": "sg-<random_string>"
      },
      {
        "ParameterKey": "VpcId",
        "ParameterValue": "vpc-<random_string>"
      },
      {
        "ParameterKey": "BootstrapIgnitionLocation",
        "ParameterValue": "s3://<bucket_name>/bootstrap.ign"
      },
      {
        "ParameterKey": "AutoRegisterELB",
        "ParameterValue": "yes"
      },
      {
        "ParameterKey": "RegisterNlbIpTargetsLambdaArn",
        "ParameterValue": "arn:aws:lambda:<aws_region>:<account_number>:function:<dns_stack_name>-RegisterNlbIpTargets-<random_string>"
      },
      {
        "ParameterKey": "ExternalApiTargetGroupArn",
        "ParameterValue": "arn:aws:elasticloadbalancing:<aws_region>:<account_number>:targetgroup/<dns_stack_name>-Exter-<random_string>"
      },
      {
        "ParameterKey": "InternalApiTargetGroupArn",
        "ParameterValue": "arn:aws:elasticloadbalancing:<aws_region>:<account_number>:targetgroup/<dns_stack_name>-Inter-<random_string>"
      },
      {
        "ParameterKey": "InternalServiceTargetGroupArn",
        "ParameterValue": "arn:aws:elasticloadbalancing:<aws_region>:<account_number>:targetgroup/<dns_stack_name>-Inter-<random_string>"
      }
    ]

    where:

    InfrastructureName
    Specifies the name for your cluster infrastructure that your Ignition config files encode for the cluster. Specify the infrastructure name that you extracted from the Ignition config file metadata, which has the format <cluster_name>-<random_string>.
    RhcosAmi
    Specifies the current Red Hat Enterprise Linux CoreOS (RHCOS) AMI to use for the bootstrap node based on your selected architecture. Specify a valid AWS::EC2::Image::Id value.
    AllowedBootstrapSshCidr
    Specifies the CIDR block to allow SSH access to the bootstrap node. Specify a CIDR block in the format x.x.x.x/16-24.
    PublicSubnet
    Specifies the public subnet in your VPC to launch the bootstrap node into. Specify the PublicSubnetIds value from the output of the CloudFormation template for the VPC.
    MasterSecurityGroupId
    Specifies the control plane security group ID for registering temporary rules. Specify the MasterSecurityGroupId value from the output of the CloudFormation template for the security group and roles.
    VpcId
    Specifies the VPC that the created resources will belong to. Specify the VpcId value from the output of the CloudFormation template for the VPC.
    BootstrapIgnitionLocation
    Specifies the location to fetch the bootstrap Ignition config file from. Specify the S3 bucket and file name in the form s3://<bucket_name>/bootstrap.ign.
    AutoRegisterELB
    Specifies whether to register a network load balancer (NLB). Specify yes or no. If you specify yes, you must give a Lambda Amazon Resource Name (ARN) value.
    RegisterNlbIpTargetsLambdaArn
    Specifies the ARN for NLB IP target registration lambda group. Specify the RegisterNlbIpTargetsLambda value from the output of the CloudFormation template for DNS and load balancing. Use arn:aws-us-gov if deploying the cluster to an AWS GovCloud region.
    ExternalApiTargetGroupArn
    Specifies the ARN for external API load balancer target group. Specify the ExternalApiTargetGroupArn value from the output of the CloudFormation template for DNS and load balancing. Use arn:aws-us-gov if deploying the cluster to an AWS GovCloud region.
    InternalApiTargetGroupArn
    Specifies the ARN for internal API load balancer target group. Specify the InternalApiTargetGroupArn value from the output of the CloudFormation template for DNS and load balancing. Use arn:aws-us-gov if deploying the cluster to an AWS GovCloud region.
    InternalServiceTargetGroupArn
    Specifies the ARN for internal service load balancer target group. Specify the InternalServiceTargetGroupArn value from the output of the CloudFormation template for DNS and load balancing. Use arn:aws-us-gov if deploying the cluster to an AWS GovCloud region.
  5. Copy the template from the CloudFormation template for the bootstrap machine section and save it as a YAML file on your computer. This template describes the bootstrap machine that your cluster requires.
  6. Optional: If you are deploying the cluster with a proxy, you must update the ignition in the template to add the ignition.config.proxy fields. Additionally, If you have added the Amazon EC2, Elastic Load Balancing, and S3 VPC endpoints to your VPC, you must add these endpoints to the noProxy field.
  7. Launch the CloudFormation template to create a stack of AWS resources that represent the bootstrap node:

    Important

    You must enter the command on a single line.

    $ aws cloudformation create-stack --stack-name <name> \
         --template-body file://<template>.yaml \
         --parameters file://<parameters>.json \
         --capabilities CAPABILITY_NAMED_IAM

    where:

    <name>
    Specifies the name for the CloudFormation stack, such as cluster-bootstrap. You need the name of this stack if you remove the cluster.
    <template>
    Specifies the relative path to and name of the CloudFormation template YAML file that you saved.
    <parameters>
    Specifies the relative path to and name of the CloudFormation parameters JSON file.
    CAPABILITY_NAMED_IAM
    You must explicitly declare this capability because the provided template creates some AWS::IAM::Role and AWS::IAM::InstanceProfile resources.

    Example output

    arn:aws:cloudformation:us-east-1:269333783861:stack/cluster-bootstrap/12944486-2add-11eb-9dee-12dace8e3a83

  8. Confirm that the template components exist:

    $ aws cloudformation describe-stacks --stack-name <name>

    After the StackStatus displays CREATE_COMPLETE, the output displays values for the following parameters. You must give these parameter values to the other CloudFormation templates that you run to create your cluster:

    BootstrapInstanceId

    The bootstrap Instance ID.

    BootstrapPublicIp

    The bootstrap node public IP address.

    BootstrapPrivateIp

    The bootstrap node private IP address.

4.3.9.1. CloudFormation template for the bootstrap machine

The bootstrap machine CloudFormation template creates the temporary Amazon Web Services (AWS) resources that the OpenShift Container Platform bootstrap process requires to initialize the control plane.

CloudFormation template for the bootstrap machine

AWSTemplateFormatVersion: 2010-09-09
Description: Template for OpenShift Cluster Bootstrap (EC2 Instance, Security Groups and IAM)

Parameters:
  InfrastructureName:
    AllowedPattern: ^([a-zA-Z][a-zA-Z0-9\-]{0,26})$
    MaxLength: 27
    MinLength: 1
    ConstraintDescription: Infrastructure name must be alphanumeric, start with a letter, and have a maximum of 27 characters.
    Description: A short, unique cluster ID used to tag cloud resources and identify items owned or used by the cluster.
    Type: String
  RhcosAmi:
    Description: Current Red Hat Enterprise Linux CoreOS AMI to use for bootstrap.
    Type: AWS::EC2::Image::Id
  AllowedBootstrapSshCidr:
    AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|1[0-9]|2[0-9]|3[0-2]))$
    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/0-32.
    Default: 0.0.0.0/0
    Description: CIDR block to allow SSH access to the bootstrap node.
    Type: String
  PublicSubnet:
    Description: The public subnet to launch the bootstrap node into.
    Type: AWS::EC2::Subnet::Id
  MasterSecurityGroupId:
    Description: The master security group ID for registering temporary rules.
    Type: AWS::EC2::SecurityGroup::Id
  VpcId:
    Description: The VPC-scoped resources will belong to this VPC.
    Type: AWS::EC2::VPC::Id
  BootstrapIgnitionLocation:
    Default: s3://my-s3-bucket/bootstrap.ign
    Description: Ignition config file location.
    Type: String
  AutoRegisterELB:
    Default: "yes"
    AllowedValues:
    - "yes"
    - "no"
    Description: Do you want to invoke NLB registration, which requires a Lambda ARN parameter?
    Type: String
  RegisterNlbIpTargetsLambdaArn:
    Description: ARN for NLB IP target registration lambda.
    Type: String
  ExternalApiTargetGroupArn:
    Description: ARN for external API load balancer target group.
    Type: String
  InternalApiTargetGroupArn:
    Description: ARN for internal API load balancer target group.
    Type: String
  InternalServiceTargetGroupArn:
    Description: ARN for internal service load balancer target group.
    Type: String
  BootstrapInstanceType:
    Description: Instance type for the bootstrap EC2 instance
    Default: "i3.large"
    Type: String

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
    - Label:
        default: "Cluster Information"
      Parameters:
      - InfrastructureName
    - Label:
        default: "Host Information"
      Parameters:
      - RhcosAmi
      - BootstrapIgnitionLocation
      - MasterSecurityGroupId
    - Label:
        default: "Network Configuration"
      Parameters:
      - VpcId
      - AllowedBootstrapSshCidr
      - PublicSubnet
    - Label:
        default: "Load Balancer Automation"
      Parameters:
      - AutoRegisterELB
      - RegisterNlbIpTargetsLambdaArn
      - ExternalApiTargetGroupArn
      - InternalApiTargetGroupArn
      - InternalServiceTargetGroupArn
    ParameterLabels:
      InfrastructureName:
        default: "Infrastructure Name"
      VpcId:
        default: "VPC ID"
      AllowedBootstrapSshCidr:
        default: "Allowed SSH Source"
      PublicSubnet:
        default: "Public Subnet"
      RhcosAmi:
        default: "Red Hat Enterprise Linux CoreOS AMI ID"
      BootstrapIgnitionLocation:
        default: "Bootstrap Ignition Source"
      MasterSecurityGroupId:
        default: "Master Security Group ID"
      AutoRegisterELB:
        default: "Use Provided ELB Automation"

Conditions:
  DoRegistration: !Equals ["yes", !Ref AutoRegisterELB]

Resources:
  BootstrapIamRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
        - Effect: "Allow"
          Principal:
            Service:
            - "ec2.amazonaws.com"
          Action:
          - "sts:AssumeRole"
      Path: "/"
      Policies:
      - PolicyName: !Join ["-", [!Ref InfrastructureName, "bootstrap", "policy"]]
        PolicyDocument:
          Version: "2012-10-17"
          Statement:
          - Effect: "Allow"
            Action: "ec2:Describe*"
            Resource: "*"
          - Effect: "Allow"
            Action: "ec2:AttachVolume"
            Resource: "*"
          - Effect: "Allow"
            Action: "ec2:DetachVolume"
            Resource: "*"
          - Effect: "Allow"
            Action: "s3:GetObject"
            Resource: "*"

  BootstrapInstanceProfile:
    Type: "AWS::IAM::InstanceProfile"
    Properties:
      Path: "/"
      Roles:
      - Ref: "BootstrapIamRole"

  BootstrapSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Cluster Bootstrap Security Group
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: 22
        ToPort: 22
        CidrIp: !Ref AllowedBootstrapSshCidr
      - IpProtocol: tcp
        ToPort: 19531
        FromPort: 19531
        CidrIp: 0.0.0.0/0
      VpcId: !Ref VpcId

  BootstrapInstance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref RhcosAmi
      IamInstanceProfile: !Ref BootstrapInstanceProfile
      InstanceType: !Ref BootstrapInstanceType
      NetworkInterfaces:
      - AssociatePublicIpAddress: "true"
        DeviceIndex: "0"
        GroupSet:
        - !Ref "BootstrapSecurityGroup"
        - !Ref "MasterSecurityGroupId"
        SubnetId: !Ref "PublicSubnet"
      UserData:
        Fn::Base64: !Sub
        - '{"ignition":{"config":{"replace":{"source":"${S3Loc}"}},"version":"3.1.0"}}'
        - {
          S3Loc: !Ref BootstrapIgnitionLocation
        }

  RegisterBootstrapApiTarget:
    Condition: DoRegistration
    Type: Custom::NLBRegister
    Properties:
      ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
      TargetArn: !Ref ExternalApiTargetGroupArn
      TargetIp: !GetAtt BootstrapInstance.PrivateIp

  RegisterBootstrapInternalApiTarget:
    Condition: DoRegistration
    Type: Custom::NLBRegister
    Properties:
      ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
      TargetArn: !Ref InternalApiTargetGroupArn
      TargetIp: !GetAtt BootstrapInstance.PrivateIp

  RegisterBootstrapInternalServiceTarget:
    Condition: DoRegistration
    Type: Custom::NLBRegister
    Properties:
      ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
      TargetArn: !Ref InternalServiceTargetGroupArn
      TargetIp: !GetAtt BootstrapInstance.PrivateIp

Outputs:
  BootstrapInstanceId:
    Description: Bootstrap Instance ID.
    Value: !Ref BootstrapInstance

  BootstrapPublicIp:
    Description: The bootstrap node public IP address.
    Value: !GetAtt BootstrapInstance.PublicIp

  BootstrapPrivateIp:
    Description: The bootstrap node private IP address.
    Value: !GetAtt BootstrapInstance.PrivateIp

4.3.10. Creating the control plane machines in AWS

To run the OpenShift Container Platform control plane, create the three control plane machines in Amazon Web Services (AWS) by using the provided CloudFormation template and a custom parameter file.

Important

The CloudFormation template creates a stack that represents three control plane nodes.

Note

If you do not use the provided CloudFormation template to create your control plane nodes, you must review the provided information and manually create the infrastructure. If your cluster does not initialize correctly, you might have to contact Red Hat support with your installation logs.

Prerequisites

  • You created the bootstrap machine.

Procedure

  1. Create a JSON file that has the parameter values that the template requires:

    [
      {
        "ParameterKey": "InfrastructureName",
        "ParameterValue": "mycluster-<random_string>"
      },
      {
        "ParameterKey": "RhcosAmi",
        "ParameterValue": "ami-<random_string>"
      },
      {
        "ParameterKey": "AutoRegisterDNS",
        "ParameterValue": "yes"
      },
      {
        "ParameterKey": "PrivateHostedZoneId",
        "ParameterValue": "<random_string>"
      },
      {
        "ParameterKey": "PrivateHostedZoneName",
        "ParameterValue": "mycluster.example.com"
      },
      {
        "ParameterKey": "Master0Subnet",
        "ParameterValue": "subnet-<random_string>"
      },
      {
        "ParameterKey": "Master1Subnet",
        "ParameterValue": "subnet-<random_string>"
      },
      {
        "ParameterKey": "Master2Subnet",
        "ParameterValue": "subnet-<random_string>"
      },
      {
        "ParameterKey": "MasterSecurityGroupId",
        "ParameterValue": "sg-<random_string>"
      },
      {
        "ParameterKey": "IgnitionLocation",
        "ParameterValue": "https://api-int.<cluster_name>.<domain_name>:22623/config/master"
      },
      {
        "ParameterKey": "CertificateAuthorities",
        "ParameterValue": "data:text/plain;charset=utf-8;base64,ABC...xYz=="
      },
      {
        "ParameterKey": "MasterInstanceProfileName",
        "ParameterValue": "<roles_stack>-MasterInstanceProfile-<random_string>"
      },
      {
        "ParameterKey": "MasterInstanceType",
        "ParameterValue": ""
      },
      {
        "ParameterKey": "AutoRegisterELB",
        "ParameterValue": "yes"
      },
      {
        "ParameterKey": "RegisterNlbIpTargetsLambdaArn",
        "ParameterValue": "arn:aws:lambda:<aws_region>:<account_number>:function:<dns_stack_name>-RegisterNlbIpTargets-<random_string>"
      },
      {
        "ParameterKey": "ExternalApiTargetGroupArn",
        "ParameterValue": "arn:aws:elasticloadbalancing:<aws_region>:<account_number>:targetgroup/<dns_stack_name>-Exter-<random_string>"
      },
      {
        "ParameterKey": "InternalApiTargetGroupArn",
        "ParameterValue": "arn:aws:elasticloadbalancing:<aws_region>:<account_number>:targetgroup/<dns_stack_name>-Inter-<random_string>"
      },
      {
        "ParameterKey": "InternalServiceTargetGroupArn",
        "ParameterValue": "arn:aws:elasticloadbalancing:<aws_region>:<account_number>:targetgroup/<dns_stack_name>-Inter-<random_string>"
      }
    ]

    where:

    InfrastructureName
    Specifies the name for your cluster infrastructure that your Ignition config files encode for the cluster. Specify the infrastructure name that you extracted from the Ignition config file metadata, which has the format <cluster_name>-<random_string>.
    RhcosAmi
    Specifies the current Red Hat Enterprise Linux CoreOS (RHCOS) AMI to use for the control plane machines based on your selected architecture. Specify an AWS::EC2::Image::Id value.
    AutoRegisterDNS
    Specifies whether to perform DNS etcd registration. Specify yes or no. If you specify yes, you must give hosted zone information.
    PrivateHostedZoneId
    Specifies the Route 53 private zone ID to register the etcd targets with. Specify the PrivateHostedZoneId value from the output of the CloudFormation template for DNS and load balancing.
    PrivateHostedZoneName
    Specifies the Route 53 zone to register the targets with. Specify <cluster_name>.<domain_name> where <domain_name> is the Route 53 base domain that you used when you generated the install-config.yaml file for the cluster. Do not include the trailing period (.) that is displayed in the AWS console.
    Master0Subnet, Master1Subnet, Master2Subnet
    Specifies a subnet, preferably private, to launch the control plane machines on. Specify a subnet from the PrivateSubnets value from the output of the CloudFormation template for DNS and load balancing.
    MasterSecurityGroupId
    Specifies the control plane security group ID to associate with control plane nodes. Specify the MasterSecurityGroupId value from the output of the CloudFormation template for the security group and roles.
    IgnitionLocation
    Specifies the location to fetch the control plane Ignition config file from. Specify the generated Ignition config file location, https://api-int.<cluster_name>.<domain_name>:22623/config/master.
    CertificateAuthorities
    Specifies the base64 encoded certificate authority string to use. Specify the value from the master.ign file that is in the installation directory. This value is the long string with the format data:text/plain;charset=utf-8;base64,ABC…​xYz==.
    MasterInstanceProfileName
    Specifies the IAM profile to associate with control plane nodes. Specify the MasterInstanceProfile parameter value from the output of the CloudFormation template for the security group and roles.
    MasterInstanceType
    Specifies the type of AWS instance to use for the control plane machines based on your selected architecture. The instance type value corresponds to the minimum resource requirements for control plane machines. For example m6i.xlarge is a type for AMD64 and m6g.xlarge is a type for ARM64.
    AutoRegisterELB
    Specifies whether to register a network load balancer (NLB). Specify yes or no. If you specify yes, you must give a Lambda Amazon Resource Name (ARN) value.
    RegisterNlbIpTargetsLambdaArn
    Specifies the ARN for NLB IP target registration lambda group. Specify the RegisterNlbIpTargetsLambda value from the output of the CloudFormation template for DNS and load balancing. Use arn:aws-us-gov if deploying the cluster to an AWS GovCloud region.
    ExternalApiTargetGroupArn
    Specifies the ARN for external API load balancer target group. Specify the ExternalApiTargetGroupArn value from the output of the CloudFormation template for DNS and load balancing. Use arn:aws-us-gov if deploying the cluster to an AWS GovCloud region.
    InternalApiTargetGroupArn
    Specifies the ARN for internal API load balancer target group. Specify the InternalApiTargetGroupArn value from the output of the CloudFormation template for DNS and load balancing. Use arn:aws-us-gov if deploying the cluster to an AWS GovCloud region.
    InternalServiceTargetGroupArn
    Specifies the ARN for internal service load balancer target group. Specify the InternalServiceTargetGroupArn value from the output of the CloudFormation template for DNS and load balancing. Use arn:aws-us-gov if deploying the cluster to an AWS GovCloud region.
  2. Copy the template from the CloudFormation template for control plane machines section and save it as a YAML file on your computer. This template describes the control plane machines that your cluster requires.
  3. If you specified an m5 instance type as the value for MasterInstanceType, add that instance type to the MasterInstanceType.AllowedValues parameter in the CloudFormation template.
  4. Launch the CloudFormation template to create a stack of AWS resources that represent the control plane nodes:

    Important

    You must enter the command on a single line.

    $ aws cloudformation create-stack --stack-name <name> \
         --template-body file://<template>.yaml \
         --parameters file://<parameters>.json

    where:

    <name>
    Specifies the name for the CloudFormation stack, such as cluster-control-plane. You need the name of this stack if you remove the cluster.
    <template>
    Specifies the relative path to and name of the CloudFormation template YAML file that you saved.
    <parameters>
    Specifies the relative path to and name of the CloudFormation parameters JSON file.

    Example output

    arn:aws:cloudformation:us-east-1:269333783861:stack/cluster-control-plane/21c7e2b0-2ee2-11eb-c6f6-0aa34627df4b

    Note

    The CloudFormation template creates a stack that represents three control plane nodes.

  5. Confirm that the template components exist:

    $ aws cloudformation describe-stacks --stack-name <name>

4.3.10.1. CloudFormation template for control plane machines

The control plane CloudFormation template creates the Amazon Web Services (AWS) resources for the three control plane machines that manage your OpenShift Container Platform cluster.

CloudFormation template for control plane machines

AWSTemplateFormatVersion: 2010-09-09
Description: Template for OpenShift Cluster Node Launch (EC2 master instances)

Parameters:
  InfrastructureName:
    AllowedPattern: ^([a-zA-Z][a-zA-Z0-9\-]{0,26})$
    MaxLength: 27
    MinLength: 1
    ConstraintDescription: Infrastructure name must be alphanumeric, start with a letter, and have a maximum of 27 characters.
    Description: A short, unique cluster ID used to tag nodes for the kubelet cloud provider.
    Type: String
  RhcosAmi:
    Description: Current Red Hat Enterprise Linux CoreOS AMI to use for bootstrap.
    Type: AWS::EC2::Image::Id
  AutoRegisterDNS:
    Default: ""
    Description: unused
    Type: String
  PrivateHostedZoneId:
    Default: ""
    Description: unused
    Type: String
  PrivateHostedZoneName:
    Default: ""
    Description: unused
    Type: String
  Master0Subnet:
    Description: The subnets, recommend private, to launch the master nodes into.
    Type: AWS::EC2::Subnet::Id
  Master1Subnet:
    Description: The subnets, recommend private, to launch the master nodes into.
    Type: AWS::EC2::Subnet::Id
  Master2Subnet:
    Description: The subnets, recommend private, to launch the master nodes into.
    Type: AWS::EC2::Subnet::Id
  MasterSecurityGroupId:
    Description: The master security group ID to associate with master nodes.
    Type: AWS::EC2::SecurityGroup::Id
  IgnitionLocation:
    Default: https://api-int.$CLUSTER_NAME.$DOMAIN:22623/config/master
    Description: Ignition config file location.
    Type: String
  CertificateAuthorities:
    Default: data:text/plain;charset=utf-8;base64,ABC...xYz==
    Description: Base64 encoded certificate authority string to use.
    Type: String
  MasterInstanceProfileName:
    Description: IAM profile to associate with master nodes.
    Type: String
  MasterInstanceType:
    Default: m5.xlarge
    Type: String

  AutoRegisterELB:
    Default: "yes"
    AllowedValues:
    - "yes"
    - "no"
    Description: Do you want to invoke NLB registration, which requires a Lambda ARN parameter?
    Type: String
  RegisterNlbIpTargetsLambdaArn:
    Description: ARN for NLB IP target registration lambda. Supply the value from the cluster infrastructure or select "no" for AutoRegisterELB.
    Type: String
  ExternalApiTargetGroupArn:
    Description: ARN for external API load balancer target group. Supply the value from the cluster infrastructure or select "no" for AutoRegisterELB.
    Type: String
  InternalApiTargetGroupArn:
    Description: ARN for internal API load balancer target group. Supply the value from the cluster infrastructure or select "no" for AutoRegisterELB.
    Type: String
  InternalServiceTargetGroupArn:
    Description: ARN for internal service load balancer target group. Supply the value from the cluster infrastructure or select "no" for AutoRegisterELB.
    Type: String

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
    - Label:
        default: "Cluster Information"
      Parameters:
      - InfrastructureName
    - Label:
        default: "Host Information"
      Parameters:
      - MasterInstanceType
      - RhcosAmi
      - IgnitionLocation
      - CertificateAuthorities
      - MasterSecurityGroupId
      - MasterInstanceProfileName
    - Label:
        default: "Network Configuration"
      Parameters:
      - VpcId
      - AllowedBootstrapSshCidr
      - Master0Subnet
      - Master1Subnet
      - Master2Subnet
    - Label:
        default: "Load Balancer Automation"
      Parameters:
      - AutoRegisterELB
      - RegisterNlbIpTargetsLambdaArn
      - ExternalApiTargetGroupArn
      - InternalApiTargetGroupArn
      - InternalServiceTargetGroupArn
    ParameterLabels:
      InfrastructureName:
        default: "Infrastructure Name"
      VpcId:
        default: "VPC ID"
      Master0Subnet:
        default: "Master-0 Subnet"
      Master1Subnet:
        default: "Master-1 Subnet"
      Master2Subnet:
        default: "Master-2 Subnet"
      MasterInstanceType:
        default: "Master Instance Type"
      MasterInstanceProfileName:
        default: "Master Instance Profile Name"
      RhcosAmi:
        default: "Red Hat Enterprise Linux CoreOS AMI ID"
      BootstrapIgnitionLocation:
        default: "Master Ignition Source"
      CertificateAuthorities:
        default: "Ignition CA String"
      MasterSecurityGroupId:
        default: "Master Security Group ID"
      AutoRegisterELB:
        default: "Use Provided ELB Automation"

Conditions:
  DoRegistration: !Equals ["yes", !Ref AutoRegisterELB]

Resources:
  Master0:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref RhcosAmi
      BlockDeviceMappings:
      - DeviceName: /dev/xvda
        Ebs:
          VolumeSize: "120"
          VolumeType: "gp2"
      IamInstanceProfile: !Ref MasterInstanceProfileName
      InstanceType: !Ref MasterInstanceType
      NetworkInterfaces:
      - AssociatePublicIpAddress: "false"
        DeviceIndex: "0"
        GroupSet:
        - !Ref "MasterSecurityGroupId"
        SubnetId: !Ref "Master0Subnet"
      UserData:
        Fn::Base64: !Sub
        - '{"ignition":{"config":{"merge":[{"source":"${SOURCE}"}]},"security":{"tls":{"certificateAuthorities":[{"source":"${CA_BUNDLE}"}]}},"version":"3.1.0"}}'
        - {
          SOURCE: !Ref IgnitionLocation,
          CA_BUNDLE: !Ref CertificateAuthorities,
        }
      Tags:
      - Key: !Join ["", ["kubernetes.io/cluster/", !Ref InfrastructureName]]
        Value: "shared"

  RegisterMaster0:
    Condition: DoRegistration
    Type: Custom::NLBRegister
    Properties:
      ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
      TargetArn: !Ref ExternalApiTargetGroupArn
      TargetIp: !GetAtt Master0.PrivateIp

  RegisterMaster0InternalApiTarget:
    Condition: DoRegistration
    Type: Custom::NLBRegister
    Properties:
      ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
      TargetArn: !Ref InternalApiTargetGroupArn
      TargetIp: !GetAtt Master0.PrivateIp

  RegisterMaster0InternalServiceTarget:
    Condition: DoRegistration
    Type: Custom::NLBRegister
    Properties:
      ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
      TargetArn: !Ref InternalServiceTargetGroupArn
      TargetIp: !GetAtt Master0.PrivateIp

  Master1:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref RhcosAmi
      BlockDeviceMappings:
      - DeviceName: /dev/xvda
        Ebs:
          VolumeSize: "120"
          VolumeType: "gp2"
      IamInstanceProfile: !Ref MasterInstanceProfileName
      InstanceType: !Ref MasterInstanceType
      NetworkInterfaces:
      - AssociatePublicIpAddress: "false"
        DeviceIndex: "0"
        GroupSet:
        - !Ref "MasterSecurityGroupId"
        SubnetId: !Ref "Master1Subnet"
      UserData:
        Fn::Base64: !Sub
        - '{"ignition":{"config":{"merge":[{"source":"${SOURCE}"}]},"security":{"tls":{"certificateAuthorities":[{"source":"${CA_BUNDLE}"}]}},"version":"3.1.0"}}'
        - {
          SOURCE: !Ref IgnitionLocation,
          CA_BUNDLE: !Ref CertificateAuthorities,
        }
      Tags:
      - Key: !Join ["", ["kubernetes.io/cluster/", !Ref InfrastructureName]]
        Value: "shared"

  RegisterMaster1:
    Condition: DoRegistration
    Type: Custom::NLBRegister
    Properties:
      ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
      TargetArn: !Ref ExternalApiTargetGroupArn
      TargetIp: !GetAtt Master1.PrivateIp

  RegisterMaster1InternalApiTarget:
    Condition: DoRegistration
    Type: Custom::NLBRegister
    Properties:
      ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
      TargetArn: !Ref InternalApiTargetGroupArn
      TargetIp: !GetAtt Master1.PrivateIp

  RegisterMaster1InternalServiceTarget:
    Condition: DoRegistration
    Type: Custom::NLBRegister
    Properties:
      ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
      TargetArn: !Ref InternalServiceTargetGroupArn
      TargetIp: !GetAtt Master1.PrivateIp

  Master2:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref RhcosAmi
      BlockDeviceMappings:
      - DeviceName: /dev/xvda
        Ebs:
          VolumeSize: "120"
          VolumeType: "gp2"
      IamInstanceProfile: !Ref MasterInstanceProfileName
      InstanceType: !Ref MasterInstanceType
      NetworkInterfaces:
      - AssociatePublicIpAddress: "false"
        DeviceIndex: "0"
        GroupSet:
        - !Ref "MasterSecurityGroupId"
        SubnetId: !Ref "Master2Subnet"
      UserData:
        Fn::Base64: !Sub
        - '{"ignition":{"config":{"merge":[{"source":"${SOURCE}"}]},"security":{"tls":{"certificateAuthorities":[{"source":"${CA_BUNDLE}"}]}},"version":"3.1.0"}}'
        - {
          SOURCE: !Ref IgnitionLocation,
          CA_BUNDLE: !Ref CertificateAuthorities,
        }
      Tags:
      - Key: !Join ["", ["kubernetes.io/cluster/", !Ref InfrastructureName]]
        Value: "shared"

  RegisterMaster2:
    Condition: DoRegistration
    Type: Custom::NLBRegister
    Properties:
      ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
      TargetArn: !Ref ExternalApiTargetGroupArn
      TargetIp: !GetAtt Master2.PrivateIp

  RegisterMaster2InternalApiTarget:
    Condition: DoRegistration
    Type: Custom::NLBRegister
    Properties:
      ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
      TargetArn: !Ref InternalApiTargetGroupArn
      TargetIp: !GetAtt Master2.PrivateIp

  RegisterMaster2InternalServiceTarget:
    Condition: DoRegistration
    Type: Custom::NLBRegister
    Properties:
      ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
      TargetArn: !Ref InternalServiceTargetGroupArn
      TargetIp: !GetAtt Master2.PrivateIp

Outputs:
  PrivateIPs:
    Description: The control-plane node private IP addresses.
    Value:
      !Join [
        ",",
        [!GetAtt Master0.PrivateIp, !GetAtt Master1.PrivateIp, !GetAtt Master2.PrivateIp]
      ]

4.3.11. Creating the worker nodes in AWS

To run application workloads on your OpenShift Container Platform cluster, create worker nodes in Amazon Web Services (AWS) by using the provided CloudFormation template.

Note

If you are installing a three-node cluster, skip this step. A three-node cluster consists of three control plane machines, which also act as compute machines.

You can use the provided CloudFormation template and a custom parameter file to create a stack of AWS resources that represent a worker node.

Important

The CloudFormation template creates a stack that represents one worker node. You must create a stack for each worker node.

Note

If you do not use the provided CloudFormation template to create your worker nodes, you must review the provided information and manually create the infrastructure. If your cluster does not initialize correctly, you might have to contact Red Hat support with your installation logs.

Prerequisites

  • You created the control plane machines.

Procedure

  1. Create a JSON file that contains the parameter values that the CloudFormation template requires:

    [
      {
        "ParameterKey": "InfrastructureName",
        "ParameterValue": "mycluster-<random_string>"
      },
      {
        "ParameterKey": "RhcosAmi",
        "ParameterValue": "ami-<random_string>"
      },
      {
        "ParameterKey": "Subnet",
        "ParameterValue": "subnet-<random_string>"
      },
      {
        "ParameterKey": "WorkerSecurityGroupId",
        "ParameterValue": "sg-<random_string>"
      },
      {
        "ParameterKey": "IgnitionLocation",
        "ParameterValue": "https://api-int.<cluster_name>.<domain_name>:22623/config/worker"
      },
      {
        "ParameterKey": "CertificateAuthorities",
        "ParameterValue": "data:text/plain;charset=utf-8;base64,ABC...xYz=="
      },
      {
        "ParameterKey": "WorkerInstanceProfileName",
        "ParameterValue": "<roles_stack>-WorkerInstanceProfile-<random_string>"
      },
      {
        "ParameterKey": "WorkerInstanceType",
        "ParameterValue": ""
      }
    ]

    where:

    InfrastructureName
    Specifies the name for your cluster infrastructure that is encoded in your Ignition config files for the cluster. Set the value to the infrastructure name that you extracted from the Ignition config file metadata, which has the format <cluster-name>-<random-string>.
    RhcosAmi
    Specifies the current Red Hat Enterprise Linux CoreOS (RHCOS) AMI to use for the worker nodes based on your selected architecture. Set the value to a valid AWS::EC2::Image::Id value.
    Subnet
    Specifies a subnet, preferably private, to start the worker nodes on. Set the value to a subnet from the PrivateSubnets value from the output of the CloudFormation template for DNS and load balancing.
    WorkerSecurityGroupId
    Specifies the worker security group ID to associate with worker nodes. Set the value to the WorkerSecurityGroupId value from the output of the CloudFormation template for the security group and roles.
    IgnitionLocation
    Specifies the location to fetch the bootstrap Ignition config file from. Set the value to the generated Ignition config location, https://api-int.<cluster_name>.<domain_name>:22623/config/worker.
    CertificateAuthorities
    Specifies the base64 encoded certificate authority string to use. Set the value to the value from the worker.ign file that is in the installation directory. This value is the long string with the format data:text/plain;charset=utf-8;base64,ABC…​xYz==.
    WorkerInstanceProfileName
    Specifies the IAM profile to associate with worker nodes. Set the value to the WorkerInstanceProfile parameter value from the output of the CloudFormation template for the security group and roles.
    WorkerInstanceType
    Specifies the type of AWS instance to use for the compute machines based on your selected architecture. The instance type value corresponds to the minimum resource requirements for compute machines. For example m6i.large is a type for AMD64 and m6g.large is a type for ARM64.
  2. Copy the template from the CloudFormation template for compute machines section of this topic and save it as a YAML file on your computer. This template describes the compute machines that your cluster requires.
  3. Optional: If you specified an m5 instance type as the value for WorkerInstanceType, add that instance type to the WorkerInstanceType.AllowedValues parameter in the CloudFormation template.
  4. Optional: If you are deploying with an AWS Marketplace image, update the Worker0.type.properties.ImageID parameter with the AMI ID that you obtained from your subscription.
  5. Use the CloudFormation template to create a stack of AWS resources that represent a worker node:

    Important

    You must enter the command on a single line.

    $ aws cloudformation create-stack --stack-name <name> \
         --template-body file://<template>.yaml \
         --parameters file://<parameters>.json

    where:

    <name>
    Specifies the name for the CloudFormation stack, such as cluster-worker-1. You need the name of this stack if you remove the cluster.
    <template>
    Specifies the relative path to and name of the CloudFormation template YAML file that you saved.
    <parameters>
    Specifies the relative path to and name of the CloudFormation parameters JSON file.

    Example output

    arn:aws:cloudformation:us-east-1:269333783861:stack/cluster-worker-1/729ee301-1c2a-11eb-348f-sd9888c65b59

    Note

    The CloudFormation template creates a stack that represents one worker node.

  6. Confirm that the template components exist:

    $ aws cloudformation describe-stacks --stack-name <name>
  7. Continue to create worker stacks until you have created enough worker machines for your cluster. You can create additional worker stacks by referencing the same template and parameter files and specifying a different stack name.

    Important

    You must create at least two worker machines, so you must create at least two stacks that use this CloudFormation template.

4.3.11.1. CloudFormation template for compute machines

The compute machine CloudFormation template creates the Amazon Web Services (AWS) resources for the worker nodes that run your OpenShift Container Platform application workloads.

CloudFormation template for compute machines

AWSTemplateFormatVersion: 2010-09-09
Description: Template for OpenShift Cluster Node Launch (EC2 worker instance)

Parameters:
  InfrastructureName:
    AllowedPattern: ^([a-zA-Z][a-zA-Z0-9\-]{0,26})$
    MaxLength: 27
    MinLength: 1
    ConstraintDescription: Infrastructure name must be alphanumeric, start with a letter, and have a maximum of 27 characters.
    Description: A short, unique cluster ID used to tag nodes for the kubelet cloud provider.
    Type: String
  RhcosAmi:
    Description: Current Red Hat Enterprise Linux CoreOS AMI to use for bootstrap.
    Type: AWS::EC2::Image::Id
  Subnet:
    Description: The subnets, recommend private, to launch the worker nodes into.
    Type: AWS::EC2::Subnet::Id
  WorkerSecurityGroupId:
    Description: The worker security group ID to associate with worker nodes.
    Type: AWS::EC2::SecurityGroup::Id
  IgnitionLocation:
    Default: https://api-int.$CLUSTER_NAME.$DOMAIN:22623/config/worker
    Description: Ignition config file location.
    Type: String
  CertificateAuthorities:
    Default: data:text/plain;charset=utf-8;base64,ABC...xYz==
    Description: Base64 encoded certificate authority string to use.
    Type: String
  WorkerInstanceProfileName:
    Description: IAM profile to associate with worker nodes.
    Type: String
  WorkerInstanceType:
    Default: m5.large
    Type: String

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
    - Label:
        default: "Cluster Information"
      Parameters:
      - InfrastructureName
    - Label:
        default: "Host Information"
      Parameters:
      - WorkerInstanceType
      - RhcosAmi
      - IgnitionLocation
      - CertificateAuthorities
      - WorkerSecurityGroupId
      - WorkerInstanceProfileName
    - Label:
        default: "Network Configuration"
      Parameters:
      - Subnet
    ParameterLabels:
      Subnet:
        default: "Subnet"
      InfrastructureName:
        default: "Infrastructure Name"
      WorkerInstanceType:
        default: "Worker Instance Type"
      WorkerInstanceProfileName:
        default: "Worker Instance Profile Name"
      RhcosAmi:
        default: "Red Hat Enterprise Linux CoreOS AMI ID"
      IgnitionLocation:
        default: "Worker Ignition Source"
      CertificateAuthorities:
        default: "Ignition CA String"
      WorkerSecurityGroupId:
        default: "Worker Security Group ID"

Resources:
  Worker0:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref RhcosAmi
      BlockDeviceMappings:
      - DeviceName: /dev/xvda
        Ebs:
          VolumeSize: "120"
          VolumeType: "gp2"
      IamInstanceProfile: !Ref WorkerInstanceProfileName
      InstanceType: !Ref WorkerInstanceType
      NetworkInterfaces:
      - AssociatePublicIpAddress: "false"
        DeviceIndex: "0"
        GroupSet:
        - !Ref "WorkerSecurityGroupId"
        SubnetId: !Ref "Subnet"
      UserData:
        Fn::Base64: !Sub
        - '{"ignition":{"config":{"merge":[{"source":"${SOURCE}"}]},"security":{"tls":{"certificateAuthorities":[{"source":"${CA_BUNDLE}"}]}},"version":"3.1.0"}}'
        - {
          SOURCE: !Ref IgnitionLocation,
          CA_BUNDLE: !Ref CertificateAuthorities,
        }
      Tags:
      - Key: !Join ["", ["kubernetes.io/cluster/", !Ref InfrastructureName]]
        Value: "shared"

Outputs:
  PrivateIP:
    Description: The compute node private IP address.
    Value: !GetAtt Worker0.PrivateIp

4.3.11.2. Creating the CloudFormation stack for compute machines

You can create a stack of Amazon Web Services (AWS) resources for the compute machines by using the provided CloudFormation template.

Important

When you use the CloudFormation template for the control plane machines, the template provisions all three control plane machines with a single stack; however, when you use the CloudFormation template to deploy the compute machines, you must create the number of stacks based on the number that you defined in the install-config.yaml file. You provision each stack once for each machine. To provision a new compute machine, you must change the stack name.

Procedure

  • To create the CloudFormation stack for compute machines, run the following command:

    $ aws cloudformation create-stack --stack-name <name> \
         --template-body file://<template>.yaml \
         --parameters file://<parameters>.json

    where:

    <name>
    Specifies the <name> with the name for the CloudFormation stack, such as cluster-worker-1. You need the name of this stack if you remove the cluster.
    <template>
    Specifies the relative path and the name of the CloudFormation template YAML file that you saved.
    <parameters>

    Specifies the relative path and the name of the JSON file for the CloudFormation parameters.

    Example output

    arn:aws:cloudformation:us-east-1:269333783861:stack/cluster-worker-1/729ee301-1c2a-11eb-348f-sd9888c65b59

After creating all required infrastructure in AWS, you can start the bootstrap sequence that initializes the OpenShift Container Platform control plane. Run the installation program to monitor the bootstrap process until the control plane is ready.

Prerequisites

  • You created the worker nodes.

Procedure

  1. Change to the directory that has the installation program and start the bootstrap process that initializes the OpenShift Container Platform control plane:

    $ ./openshift-install wait-for bootstrap-complete --dir <installation_directory> \
        --log-level=info
    • For <installation_directory>, specify the path to the directory that you stored the installation files in.
    • To view different installation details, specify warn, debug, or error instead of info.

      Example output

      INFO Waiting up to 20m0s for the Kubernetes API at https://api.mycluster.example.com:6443...
      INFO API v1.34.2 up
      INFO Waiting up to 45m0s for bootstrapping to complete...
      INFO It is now safe to remove the bootstrap resources
      INFO Time elapsed: 1s

      The bootstrapping completion wait time varies per platform.

      If the command exits without a FATAL warning, your OpenShift Container Platform control plane has initialized.

      Note

      After the control plane initializes, it sets up the compute nodes and installs additional services in the form of Operators.

4.3.13. Logging in to the cluster by using the CLI

To log in to your cluster as the default system user, export the kubeconfig file. This configuration enables the CLI to authenticate and connect to the specific API server created during OpenShift Container Platform installation.

The kubeconfig file is specific to a cluster and OpenShift Container Platform generates it during installation.

Prerequisites

  • You deployed an OpenShift Container Platform cluster.
  • You installed the OpenShift CLI (oc).

Procedure

  1. Export the kubeadmin credentials by running the following command:

    $ export KUBECONFIG=<installation_directory>/auth/kubeconfig

    where:

    <installation_directory>
    Specifies the path to the directory that stores the installation files.
  2. Verify you can run oc commands successfully using the exported configuration by running the following command:

    $ oc whoami

    Example output

    system:admin

Next steps

  • "Customize your cluster"
  • "Remote health reporting"

4.3.14. Approve the certificate signing requests for your machines

To allow newly added machines to join your OpenShift Container Platform cluster, confirm that the cluster approves pending certificate signing requests (CSRs), or approve them yourself. Approve client requests first, then server requests.

Prerequisites

  • You added machines to your cluster.

Procedure

  1. Confirm that the cluster recognizes the machines:

    $ oc get nodes

    Example output

    NAME      STATUS    ROLES   AGE  VERSION
    master-0  Ready     master  63m  v1.34.2
    master-1  Ready     master  63m  v1.34.2
    master-2  Ready     master  64m  v1.34.2

    The output lists all of the machines that you created.

    Note

    The preceding output might not include the compute nodes until you approve some CSRs.

  2. Review the pending CSRs and ensure that you see the client requests with the Pending or Approved status for each machine that you added to the cluster:

    $ oc get csr

    Example output

    NAME        AGE     REQUESTOR                                                                   CONDITION
    csr-8b2br   15m     system:serviceaccount:openshift-machine-config-operator:node-bootstrapper   Pending
    csr-8vnps   15m     system:serviceaccount:openshift-machine-config-operator:node-bootstrapper   Pending
    ...

    In this example, two machines are joining the cluster. You might see more approved CSRs in the list.

  3. If the CSRs were not approved, after all of the pending CSRs for the machines you added are in Pending status, approve the CSRs for your cluster machines:

    Note

    You must approve your CSRs within an hour of adding the machines to the cluster. If you do not approve them within an hour, the certificates rotate, and more than two certificates are present for each node. You must approve all of these certificates. After you approve the client CSR, the kubelet creates a secondary CSR for the serving certificate, which requires manual approval. The machine-approver then automatically approves later serving certificate renewal requests if the kubelet requests a new certificate with the same parameters.

    Note

    For clusters running on platforms that are not machine API enabled, such as bare metal and other user-provisioned infrastructure, you must implement a method of automatically approving the kubelet serving certificate requests (CSRs). If you do not approve a request, the oc exec, oc rsh, and oc logs commands cannot succeed, because the API server requires a serving certificate when it connects to the kubelet. Any operation that contacts the kubelet endpoint requires this certificate approval to be in place. The method must watch for new CSRs, confirm that the node-bootstrapper service account in the system:node or system:admin groups submitted the CSR, and confirm the identity of the node.

    • To approve them individually, run the following command for each valid CSR:

      $ oc adm certificate approve <csr_name>

      where:

      <csr_name>
      Specifies the name of a CSR from the list of current CSRs.
    • To approve all pending CSRs, run the following command:

      $ oc get csr -o go-template='{{range .items}}{{if not .status}}{{.metadata.name}}{{"\n"}}{{end}}{{end}}' | xargs --no-run-if-empty oc adm certificate approve
      Note

      Some Operators might not become available until you approve some CSRs.

  4. After you approve your client requests, review the server requests for each machine that you added to the cluster:

    $ oc get csr

    Example output

    NAME        AGE     REQUESTOR                                                                   CONDITION
    csr-bfd72   5m26s   system:node:ip-10-0-50-126.us-east-2.compute.internal                       Pending
    csr-c57lv   5m26s   system:node:ip-10-0-95-157.us-east-2.compute.internal                       Pending
    ...

  5. If the remaining CSRs are not approved, and are in the Pending status, approve the CSRs for your cluster machines:

    • To approve them individually, run the following command for each valid CSR:

      $ oc adm certificate approve <csr_name>

      where:

      <csr_name>
      Specifies the name of a CSR from the list of current CSRs.
    • To approve all pending CSRs, run the following command:

      $ oc get csr -o go-template='{{range .items}}{{if not .status}}{{.metadata.name}}{{"\n"}}{{end}}{{end}}' | xargs oc adm certificate approve
  6. After you approve all client and server CSRs, the machines have the Ready status. Verify this by running the following command:

    $ oc get nodes

    Example output

    NAME      STATUS    ROLES   AGE  VERSION
    master-0  Ready     master  73m  v1.34.2
    master-1  Ready     master  73m  v1.34.2
    master-2  Ready     master  74m  v1.34.2
    worker-0  Ready     worker  11m  v1.34.2
    worker-1  Ready     worker  11m  v1.34.2

    Note

    You might need to wait a few minutes after approval of the server CSRs for the machines to reach the Ready status.

4.3.15. Initial Operator configuration

After the control plane initializes, you must immediately configure some Operators so that they all become available.

Prerequisites

  • Your control plane has initialized.

Procedure

  1. Watch the cluster components come online:

    $ watch -n5 oc get clusteroperators

    Example output

    NAME                                       VERSION   AVAILABLE   PROGRESSING   DEGRADED   SINCE
    authentication                             4.21.0    True        False         False      19m
    baremetal                                  4.21.0    True        False         False      37m
    cloud-credential                           4.21.0    True        False         False      40m
    cluster-autoscaler                         4.21.0    True        False         False      37m
    config-operator                            4.21.0    True        False         False      38m
    console                                    4.21.0    True        False         False      26m
    csi-snapshot-controller                    4.21.0    True        False         False      37m
    dns                                        4.21.0    True        False         False      37m
    etcd                                       4.21.0    True        False         False      36m
    image-registry                             4.21.0    True        False         False      31m
    ingress                                    4.21.0    True        False         False      30m
    insights                                   4.21.0    True        False         False      31m
    kube-apiserver                             4.21.0    True        False         False      26m
    kube-controller-manager                    4.21.0    True        False         False      36m
    kube-scheduler                             4.21.0    True        False         False      36m
    kube-storage-version-migrator              4.21.0    True        False         False      37m
    machine-api                                4.21.0    True        False         False      29m
    machine-approver                           4.21.0    True        False         False      37m
    machine-config                             4.21.0    True        False         False      36m
    marketplace                                4.21.0    True        False         False      37m
    monitoring                                 4.21.0    True        False         False      29m
    network                                    4.21.0    True        False         False      38m
    node-tuning                                4.21.0    True        False         False      37m
    openshift-apiserver                        4.21.0    True        False         False      32m
    openshift-controller-manager               4.21.0    True        False         False      30m
    openshift-samples                          4.21.0    True        False         False      32m
    operator-lifecycle-manager                 4.21.0    True        False         False      37m
    operator-lifecycle-manager-catalog         4.21.0    True        False         False      37m
    operator-lifecycle-manager-packageserver   4.21.0    True        False         False      32m
    service-ca                                 4.21.0    True        False         False      38m
    storage                                    4.21.0    True        False         False      37m

  2. Configure the Operators that are not available.

4.3.15.1. Image registry storage configuration

Amazon Web Services provides default storage, which means the Image Registry Operator is available after installation. However, if the Registry Operator cannot create an S3 bucket and automatically configure storage, you must manually configure registry storage.

Configure a persistent volume, which is required for production clusters. Where applicable, you can configure an empty directory as the storage location for non-production clusters.

You can also allow the image registry to use block storage types by using the Recreate rollout strategy during upgrades.

If the Registry Operator cannot automatically create and configure an Amazon S3 bucket during installation, you must manually configure registry storage for your cluster.

Warning

To secure your registry images in Amazon Web Services (AWS), block public access to the S3 bucket.

Prerequisites

  • You have a cluster on AWS with user-provisioned infrastructure.
  • For Amazon S3 storage, the secret must contain two keys:

    • REGISTRY_STORAGE_S3_ACCESSKEY
    • REGISTRY_STORAGE_S3_SECRETKEY

Procedure

  1. Set up a Bucket Lifecycle Policy to cancel incomplete multipart uploads that are one day old.
  2. Enter the storage configuration in configs.imageregistry.operator.openshift.io/cluster:

    $ oc edit configs.imageregistry.operator.openshift.io/cluster

    Example configuration

    apiVersion: imageregistry.operator.openshift.io/v1
    kind: Config
    metadata:
      name: cluster
    spec:
      storage:
        s3:
          bucket: <bucket_name>
          region: <region_name>

You must configure storage for the Image Registry Operator. For non-production clusters, you can set the image registry to an empty directory, but you lose all images if you restart the registry.

Procedure

  • To set the image registry storage to an empty directory:

    $ oc patch configs.imageregistry.operator.openshift.io cluster --type merge --patch '{"spec":{"storage":{"emptyDir":{}}}}'
    Warning

    Configure this option only for non-production clusters.

    If you run this command before the Image Registry Operator initializes its components, the oc patch command fails with the following error:

    Example output

    Error from server (NotFound): configs.imageregistry.operator.openshift.io "cluster" not found

    Wait a few minutes and run the command again.

4.3.16. Deleting the bootstrap resources

After completing the initial Operator configuration for your OpenShift Container Platform cluster, you can delete the bootstrap resources from AWS to free up capacity and reduce costs.

Prerequisites

  • You completed the initial Operator configuration for your cluster.

Procedure

  1. Delete the bootstrap resources. If you used the CloudFormation template, delete its stack:

    • Delete the stack by using the AWS CLI:

      $ aws cloudformation delete-stack --stack-name <name>

      <name> is the name of your bootstrap stack.

    • Delete the stack by using the AWS CloudFormation console.

4.3.17. Creating the Ingress DNS records

If you removed the DNS zone configuration during installation, you must manually create DNS records that point to the Ingress load balancer so that your OpenShift Container Platform cluster routes are reachable.

You can create either a wildcard record or specific records. While the following procedure uses A records, you can use other record types that you require, such as CNAME or alias.

Prerequisites

Procedure

  1. Find the routes to create.

    • To create a wildcard record, use *.apps.<cluster_name>.<domain_name>, where <cluster_name> is your cluster name, and <domain_name> is the Route 53 base domain for your OpenShift Container Platform cluster.
    • To create specific records, you must create a record for each route that your cluster uses, as shown in the output of the following command:

      $ oc get --all-namespaces -o jsonpath='{range .items[*]}{range .status.ingress[*]}{.host}{"\n"}{end}{end}' routes

      Example output

      oauth-openshift.apps.<cluster_name>.<domain_name>
      console-openshift-console.apps.<cluster_name>.<domain_name>
      downloads-openshift-console.apps.<cluster_name>.<domain_name>
      alertmanager-main-openshift-monitoring.apps.<cluster_name>.<domain_name>
      prometheus-k8s-openshift-monitoring.apps.<cluster_name>.<domain_name>

  2. Retrieve the Ingress Operator load balancer status and note the value of the external IP address that it uses, which the EXTERNAL-IP column displays:

    $ oc -n openshift-ingress get service router-default

    Example output

    NAME             TYPE           CLUSTER-IP      EXTERNAL-IP                            PORT(S)                      AGE
    router-default   LoadBalancer   172.30.62.215   ab3...28.us-east-2.elb.amazonaws.com   80:31499/TCP,443:30693/TCP   5m

  3. Locate the hosted zone ID for the load balancer:

    $ aws elb describe-load-balancers | jq -r '.LoadBalancerDescriptions[] | select(.DNSName == "<external_ip>").CanonicalHostedZoneNameID'

    For <external_ip>, specify the value of the external IP address of the Ingress Operator load balancer that you obtained.

    Example output

    Z3AADJGX6KTTL2

    The output of this command is the load balancer hosted zone ID.

  4. Obtain the public hosted zone ID for your cluster’s domain:

    $ aws route53 list-hosted-zones-by-name \
                --dns-name "<domain_name>" \
                --query 'HostedZones[? Config.PrivateZone != `true` && Name == `<domain_name>.`].Id'
                --output text

    For <domain_name>, specify the Route 53 base domain for your OpenShift Container Platform cluster.

    Example output

    /hostedzone/Z3URY6TWQ91KVV

    The command output displays the public hosted zone ID for your domain. In this example, it is Z3URY6TWQ91KVV.

  5. Add the alias records to your private zone:

    $ aws route53 change-resource-record-sets --hosted-zone-id "<private_hosted_zone_id>" --change-batch '{
    >   "Changes": [
    >     {
    >       "Action": "CREATE",
    >       "ResourceRecordSet": {
    >         "Name": "\\052.apps.<cluster_domain>",
    >         "Type": "A",
    >         "AliasTarget":{
    >           "HostedZoneId": "<hosted_zone_id>",
    >           "DNSName": "<external_ip>.",
    >           "EvaluateTargetHealth": false
    >         }
    >       }
    >     }
    >   ]
    > }'

    where:

    <private_hosted_zone_id>
    Specifies the value from the output of the CloudFormation template for DNS and load balancing.
    <cluster_domain>
    Specifies the domain or subdomain that you use with your OpenShift Container Platform cluster.
    <hosted_zone_id>
    Specifies the public hosted zone ID for the load balancer that you obtained.
    <external_ip>
    Specifies the value of the external IP address of the Ingress Operator load balancer. Ensure that you include the trailing period (.) in this parameter value.
  6. Add the records to your public zone:

    $ aws route53 change-resource-record-sets --hosted-zone-id "<public_hosted_zone_id>"" --change-batch '{
    >   "Changes": [
    >     {
    >       "Action": "CREATE",
    >       "ResourceRecordSet": {
    >         "Name": "\\052.apps.<cluster_domain>",
    >         "Type": "A",
    >         "AliasTarget":{
    >           "HostedZoneId": "<hosted_zone_id>",
    >           "DNSName": "<external_ip>.",
    >           "EvaluateTargetHealth": false
    >         }
    >       }
    >     }
    >   ]
    > }'

    where: <public_hosted_zone_id>:: Specifies the public hosted zone for your domain. <cluster_domain>:: Specifies the domain or subdomain that you use with your OpenShift Container Platform cluster. <hosted_zone_id>:: Specifies the public hosted zone ID for the load balancer that you obtained. <external_ip>:: Specifies the value of the external IP address of the Ingress Operator load balancer. Ensure that you include the trailing period (.) in this parameter value.

To finish installing OpenShift Container Platform on user-provisioned AWS infrastructure, monitor the deployment until it completes successfully.

Prerequisites

  • You removed the bootstrap node for an OpenShift Container Platform cluster on user-provisioned AWS infrastructure.
  • You installed the oc CLI.

Procedure

  • From the directory that has the installation program, complete the cluster installation:

    $ ./openshift-install --dir <installation_directory> wait-for install-complete

    For <installation_directory>, specify the path to the directory that you stored the installation files in.

    Example output

    INFO Waiting up to 40m0s for the cluster at https://api.mycluster.example.com:6443 to initialize...
    INFO Waiting up to 10m0s for the openshift-console route to be created...
    INFO Install complete!
    INFO To access the cluster as the system:admin user when using 'oc', run 'export KUBECONFIG=/home/myuser/install_dir/auth/kubeconfig'
    INFO Access the OpenShift web-console here: https://console-openshift-console.apps.mycluster.example.com
    INFO Login to the console with user: "kubeadmin", and password: "password"
    INFO Time elapsed: 1s

    Important
    • The Ignition config files that the installation program generates contain certificates that expire after 24 hours, which are then renewed at that time. If you shut down the cluster before renewing the certificates and later restart it after the 24 hours have elapsed, the cluster automatically recovers the expired certificates. The exception is that you must manually approve the pending node-bootstrapper certificate signing requests (CSRs) to recover kubelet certificates. See the documentation for Recovering from expired control plane certificates for more information.
    • Use Ignition config files within 12 hours after the installation program generates them because the 24-hour certificate rotates from 16 to 22 hours after you install the cluster. By using the Ignition config files within 12 hours, you can avoid installation failure if the certificate update runs during installation.

4.3.19. Logging in to the cluster by using the web console

To verify that your cluster deployed successfully and access its features, log in to the OpenShift Container Platform web console as the kubeadmin user.

Prerequisites

  • You have access to the installation host.
  • You completed a cluster installation and all cluster Operators are available.

Procedure

  1. Obtain the password for the kubeadmin user from the kubeadmin-password file on the installation host:

    $ cat <installation_directory>/auth/kubeadmin-password
    Note

    Or, you can obtain the kubeadmin password from the <installation_directory>/.openshift_install.log log file on the installation host.

  2. List the OpenShift Container Platform web console route:

    $ oc get routes -n openshift-console | grep 'console-openshift'
    Note

    Or, you can obtain the OpenShift Container Platform route from the <installation_directory>/.openshift_install.log log file on the installation host.

    Example output

    console     console-openshift-console.apps.<cluster_name>.<base_domain>            console     https   reencrypt/Redirect   None

  3. Navigate to the route detailed in the output of the preceding command in a web browser and log in as the kubeadmin user.

In OpenShift Container Platform version 4.21, you can install a cluster on Amazon Web Services (AWS) using infrastructure that you provide and an internal mirror of the installation release content.

Important

While you can install an OpenShift Container Platform cluster by using mirrored installation release content, your cluster still requires internet access to use the AWS APIs.

One way to create this infrastructure is to use the provided CloudFormation templates. You can change the templates to customize your infrastructure or use the information that they contain to create AWS objects according to your company’s policies.

Important

The steps for performing a user-provisioned infrastructure installation are an example only. Installing a cluster with infrastructure you provide requires knowledge of the cloud provider and the installation process of OpenShift Container Platform. Several CloudFormation templates help you complete these steps or model your own. You are also free to create the required resources through other methods; the templates are just an example.

4.4.1. Prerequisites

Before you install OpenShift Container Platform on Amazon Web Services (AWS) in a restricted network, ensure that you have prepared your user-provisioned infrastructure, configured mirror registries for disconnected installation, and met all account and networking requirements.

The following list outlines the prerequisites to complete:

  • You reviewed details about the OpenShift Container Platform installation and update processes.
  • You read the documentation on selecting a cluster installation method and preparing it for users.
  • You created a mirror registry on your mirror host and obtained the imageContentSources data for your version of OpenShift Container Platform.

    Important

    Because the installation media is on the mirror host, you can use that computer to complete all installation steps.

  • You configured an AWS account to host the cluster.

    Important

    If you have an AWS profile stored on your computer, it must not use a temporary session token that you generated while using a multi-factor authentication device. The cluster continues to use your current AWS credentials to create AWS resources for the entire life of the cluster, so you must use key-based, long-term credentials. You must generate appropriate keys. You can supply the keys when you run the installation program.

  • You prepared the user-provisioned infrastructure.
  • You downloaded the AWS CLI and installed it on your computer.
  • If you use a firewall and plan to use the Telemetry service, you configured the firewall to allow the sites that your cluster requires access to.

    Note

    Be sure to also review this site list if you are configuring a proxy.

  • If the cloud identity and access management (IAM) APIs are not accessible in your environment, or if you do not want to store an administrator-level credential secret in the kube-system namespace, you can manually create and maintain long-term credentials.

4.4.2. About installations in restricted networks

You can install OpenShift Container Platform 4.21 in a restricted network without an active internet connection to obtain software components. Restricted network installations can use installer-provisioned or user-provisioned infrastructure, depending on the cloud platform to which you are installing the cluster.

If you choose to perform a restricted network installation on a cloud platform, you still require access to its cloud APIs. Some cloud functions, such as Amazon Web Service’s Route 53 DNS and IAM services, require internet access. Depending on your network, you might require less internet access for an installation on bare-metal hardware, Nutanix, or on VMware vSphere.

To complete a restricted network installation, you must create a registry that mirrors the contents of the OpenShift image registry and contains the installation media. You can create this registry on a mirror host, which can access both the internet and your closed network, or by using other methods that meet your restrictions.

Important

Because of the complexity of the configuration for user-provisioned installations, consider completing a standard user-provisioned infrastructure installation before you try a restricted network installation using user-provisioned infrastructure. Completing this test installation might make it easier to isolate and troubleshoot any issues that might arise during your installation in a restricted network.

4.4.2.1. Additional limits

Clusters in restricted networks have the following additional limitations and restrictions:

  • The ClusterVersion status includes an Unable to retrieve available updates error.
  • By default, you cannot use the contents of the Developer Catalog because you cannot access the required image stream tags.

4.4.3. Creating the installation files for AWS

To install OpenShift Container Platform on Amazon Web Services by using user-provisioned infrastructure, you must generate the files that the installation program needs to deploy your cluster and modify them so that the cluster creates only the machines that it will use.

You generate and customize the install-config.yaml file, Kubernetes manifests, and Ignition config files. You also have the option to first set up a separate var partition during the preparation phases of installation.

4.4.3.1. Creating a separate /var partition

To isolate growing storage for containers, etcd, or logs, you can optionally create a separate /var partition on worker nodes before you generate Ignition configs.

It is recommended that disk partitioning for OpenShift Container Platform be left to the installation program. However, there are cases where you might want to create separate partitions in a part of the filesystem that you expect to grow.

OpenShift Container Platform supports the addition of a single partition to attach storage to either the /var partition or a subdirectory of /var. For example:

  • /var/lib/containers: Holds container-related content that can grow as more images and containers are added to a system.
  • /var/lib/etcd: Holds data that you might want to keep separate for purposes such as performance optimization of etcd storage.
  • /var: Holds data that you might want to keep separate for purposes such as auditing.

Storing the contents of a /var directory separately makes it easier to grow storage for those areas as needed and reinstall OpenShift Container Platform at a later date and keep that data intact. With this method, you will not have to pull all your containers again, nor will you have to copy massive log files when you update systems.

Because /var must be in place before a fresh installation of Red Hat Enterprise Linux CoreOS (RHCOS), the following procedure sets up the separate /var partition by creating a machine config manifest that is inserted during the openshift-install preparation phases of an OpenShift Container Platform installation.

Important

If you follow the steps to create a separate /var partition in this procedure, it is not necessary to create the Kubernetes manifest and Ignition config files again as described later in this section.

Procedure

  1. Create a directory to hold the OpenShift Container Platform installation files:

    $ mkdir $HOME/clusterconfig
  2. Run openshift-install to create a set of files in the manifest and openshift subdirectories. Answer the system questions as you are prompted:

    $ openshift-install create manifests --dir $HOME/clusterconfig

    Example output

    ? SSH Public Key ...
    INFO Credentials loaded from the "myprofile" profile in file "/home/myuser/.aws/credentials"
    INFO Consuming Install Config from target directory
    INFO Manifests created in: $HOME/clusterconfig/manifests and $HOME/clusterconfig/openshift

  3. Optional: Confirm that the installation program created manifests in the clusterconfig/openshift directory:

    $ ls $HOME/clusterconfig/openshift/

    Example output

    99_kubeadmin-password-secret.yaml
    99_openshift-cluster-api_master-machines-0.yaml
    99_openshift-cluster-api_master-machines-1.yaml
    99_openshift-cluster-api_master-machines-2.yaml
    ...

  4. Create a Butane config that configures the additional partition. For example, name the file $HOME/clusterconfig/98-var-partition.bu, change the disk device name to the name of the storage device on the worker systems, and set the storage size as appropriate. This example places the /var directory on a separate partition:

    variant: openshift
    version: 4.21.0
    metadata:
      labels:
        machineconfiguration.openshift.io/role: worker
      name: 98-var-partition
    storage:
      disks:
      - device: /dev/disk/by-id/<device_name>
        partitions:
        - label: var
          start_mib: <partition_start_offset>
          size_mib: <partition_size>
          number: 5
      filesystems:
        - device: /dev/disk/by-partlabel/var
          path: /var
          format: xfs
          mount_options: [defaults, prjquota]
          with_mount_unit: true

    where:

    <device_name>
    Specifies the storage device name of the disk that you want to partition.
    <partition_start_offset>
    Specifies the start_mib parameter. When adding a data partition to the boot disk, a minimum value of 25000 MiB (Mebibytes) is recommended. The root file system is automatically resized to fill all available space up to the specified offset. If no value is specified, or if the specified value is smaller than the recommended minimum, the resulting root file system will be too small, and future reinstalls of RHCOS might overwrite the beginning of the data partition.
    <partition_size>
    Specifies the size of the data partition in mebibytes.
    storage.filesystems.mount_options

    The prjquota mount option must be enabled for filesystems used for container storage.

    Note

    When creating a separate /var partition, you cannot use different instance types for worker nodes, if the different instance types do not have the same device name.

  5. Create a manifest from the Butane config and save it to the clusterconfig/openshift directory. For example, run the following command:

    $ butane $HOME/clusterconfig/98-var-partition.bu -o $HOME/clusterconfig/openshift/98-var-partition.yaml
  6. Run openshift-install again to create Ignition configs from a set of files in the manifest and openshift subdirectories:

    $ openshift-install create ignition-configs --dir $HOME/clusterconfig
    $ ls $HOME/clusterconfig/
    auth  bootstrap.ign  master.ign  metadata.json  worker.ign

    You can now use the Ignition config files as input to the installation procedures to install Red Hat Enterprise Linux CoreOS (RHCOS) systems.

4.4.3.2. Creating the installation configuration file

Generate and customize the installation configuration file that the installation program needs to deploy your cluster.

Prerequisites

  • You obtained the OpenShift Container Platform installation program for user-provisioned infrastructure and the pull secret for your cluster. For a restricted network installation, these files are on your mirror host.
  • You checked that you are deploying your cluster to an Amazon Web Services (AWS) Region with an accompanying Red Hat Enterprise Linux CoreOS (RHCOS) AMI published by Red Hat. If you are deploying to an AWS Region that requires a custom AMI, such as an AWS GovCloud Region, you must create the install-config.yaml file manually.

Procedure

  1. Create the install-config.yaml file.

    1. Change to the directory that contains the installation program and run the following command:

      $ ./openshift-install create install-config --dir <installation_directory>

      For <installation_directory>, specify the directory name to store the files that the installation program creates.

      Important

      Specify an empty directory. Some installation assets, such as bootstrap X.509 certificates have short expiration intervals, so you must not reuse an installation directory. If you want to reuse individual files from another cluster installation, you can copy them into your directory. However, the file names for the installation assets might change between releases. Use caution when copying installation files from an earlier OpenShift Container Platform version.

    2. At the prompts, provide the configuration details for your cloud:

      1. Optional: Select an SSH key to use to access your cluster machines.

        Note

        For production OpenShift Container Platform clusters on which you want to perform installation debugging or disaster recovery, specify an SSH key that your ssh-agent process uses.

      2. Select aws as the platform to target.
      3. If you do not have an AWS profile stored on your computer, enter the AWS access key ID and secret access key for the user that you configured to run the installation program.

        Note

        The AWS access key ID and secret access key are stored in ~/.aws/credentials in the home directory of the current user on the installation host. You are prompted for the credentials by the installation program if the credentials for the exported profile are not present in the file. Any credentials that you provide to the installation program are stored in the file.

      4. Select the AWS Region to deploy the cluster to.
      5. Select the base domain for the Route 53 service that you configured for your cluster.
      6. Enter a descriptive name for your cluster.
      7. Paste the pull secret from Red Hat OpenShift Cluster Manager.
  2. Edit the install-config.yaml file to give the additional information that is required for an installation in a restricted network.

    1. Update the pullSecret value to contain the authentication information for your registry:

      pullSecret: '{"auths":{"<local_registry>": {"auth": "<credentials>","email": "you@example.com"}}}'

      For <local_registry>, specify the registry domain name, and optionally the port, that your mirror registry uses to serve content. For example registry.example.com or registry.example.com:5000. For <credentials>, specify the base64-encoded user name and password for your mirror registry.

    2. Add the additionalTrustBundle parameter and value. The value must be the contents of the certificate file that you used for your mirror registry. The certificate file can be an existing, trusted certificate authority or the self-signed certificate that you generated for the mirror registry.

      additionalTrustBundle: |
        -----BEGIN CERTIFICATE-----
        ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
        -----END CERTIFICATE-----
    3. Add the image content resources:

      imageContentSources:
      - mirrors:
        - <local_registry>/<local_repository_name>/release
        source: quay.io/openshift-release-dev/ocp-release
      - mirrors:
        - <local_registry>/<local_repository_name>/release
        source: quay.io/openshift-release-dev/ocp-v4.0-art-dev

      Use the imageContentSources section from the output of the command to mirror the repository or the values that you used when you mirrored the content from the media that you brought into your restricted network.

    4. Optional: Set the publishing strategy to Internal:

      publish: Internal

      By setting this option, you create an internal Ingress Controller and a private load balancer.

  3. Optional: Back up the install-config.yaml file.

    Important

    The install-config.yaml file is consumed during the installation process. If you want to reuse the file, you must back it up now.

4.4.3.3. Configuring the cluster-wide proxy during installation

Production environments can deny direct access to the internet and instead have an HTTP or HTTPS proxy available. You can configure a new OpenShift Container Platform cluster to use a proxy by configuring the proxy settings in the install-config.yaml file.

Prerequisites

  • You have an existing install-config.yaml file.
  • You have reviewed the sites that your cluster requires access to and determined whether any of them need to bypass the proxy. By default, the proxy handles all cluster egress traffic, including calls to hosting cloud provider APIs. You added sites to the Proxy object’s spec.noProxy field to bypass the proxy if necessary.

    Note

    The Proxy object status.noProxy field includes the values of the networking.machineNetwork[].cidr, networking.clusterNetwork[].cidr, and networking.serviceNetwork[] fields from your installation configuration.

    For installations on Amazon Web Services (AWS), Google Cloud, Microsoft Azure, and Red Hat OpenStack Platform (RHOSP), the Proxy object status.noProxy field also includes the instance metadata endpoint (169.254.169.254).

Procedure

  1. Edit your install-config.yaml file and add the proxy settings. For example:

    apiVersion: v1
    baseDomain: my.domain.com
    proxy:
      httpProxy: http://<username>:<pswd>@<ip>:<port>
      httpsProxy: https://<username>:<pswd>@<ip>:<port>
      noProxy: ec2.<aws_region>.amazonaws.com,elasticloadbalancing.<aws_region>.amazonaws.com,s3.<aws_region>.amazonaws.com
    additionalTrustBundle: |
        -----BEGIN CERTIFICATE-----
        <MY_TRUSTED_CA_CERT>
        -----END CERTIFICATE-----
    additionalTrustBundlePolicy: <policy_to_add_additionalTrustBundle>
    # ...

    where:

    proxy.httpProxy
    Specifies a proxy URL to use for creating HTTP connections outside the cluster. The URL scheme must be http.
    proxy.httpsProxy
    Specifies a proxy URL to use for creating HTTPS connections outside the cluster.
    proxy.noProxy
    Specifies a comma-separated list of destination domain names, IP addresses, or other network CIDRs to exclude from proxying. Preface a domain with . to match subdomains only. For example, .y.com matches x.y.com, but not y.com. Use * to bypass the proxy for all destinations. If you have added the Amazon EC2, Elastic Load Balancing, and S3 VPC endpoints to your VPC, you must add these endpoints to the noProxy field.
    additionalTrustBundle
    If you specify this value, the installation program generates a config map named user-ca-bundle in the openshift-config namespace to hold the additional CA certificates. If you specify additionalTrustBundle and at least one proxy setting, the Proxy object references the user-ca-bundle config map in the trustedCA field. The Cluster Network Operator then creates a trusted-ca-bundle config map that merges the contents specified for the trustedCA parameter with the RHCOS trust bundle. You must set the additionalTrustBundle field unless an authority from the RHCOS trust bundle signs the proxy’s identity certificate.
    additionalTrustBundlePolicy

    Specifies the policy that determines the configuration of the Proxy object to reference the user-ca-bundle config map in the trustedCA field. The allowed values are Proxyonly and Always. Use Proxyonly to reference the user-ca-bundle config map only when you configure an http/https proxy. Use Always to always reference the user-ca-bundle config map. The default value is Proxyonly. Optional parameter.

    Note

    The installation program does not support the proxy readinessEndpoints field.

    Note

    If the installation program times out, restart and then complete the deployment by using the wait-for command of the installation program. For example:

    $ ./openshift-install wait-for install-complete --log-level debug
  2. Save the file and reference it when installing OpenShift Container Platform.

    The installation program creates a cluster-wide proxy named cluster that uses the proxy settings in the install-config.yaml file. If you do not give proxy settings, the installation program still creates a cluster Proxy object, but it has a nil spec.

    Note

    Only the Proxy object named cluster is supported, and you cannot create additional proxies.

4.4.3.4. Creating the Kubernetes manifest and Ignition config files

Because you manually provision infrastructure, you must generate the Kubernetes manifest and Ignition config files that the cluster requires.

The installation program converts the installation configuration into Kubernetes manifests and then wraps them into Ignition configuration files. You use these Ignition files to configure the cluster machines.

Important
  • The Ignition config files that the OpenShift Container Platform installation program generates contain certificates that expire after 24 hours, which the system then renews. If you shut down the cluster before the system renews the certificates and you later restart the cluster after the 24 hours have elapsed, the cluster automatically recovers the expired certificates. The exception is that you must manually approve the pending node-bootstrapper certificate signing requests (CSRs) to recover kubelet certificates. See the documentation for Recovering from expired control plane certificates for more information.
  • Use Ignition config files within 12 hours after you generate them, because the 24-hour certificate rotates from 16 to 22 hours after you install the cluster. By using the Ignition config files within 12 hours, you can avoid installation failure if the certificate update runs during installation.

Prerequisites

  • You obtained the OpenShift Container Platform installation program. For a restricted network installation, these files are on your mirror host.
  • You created the install-config.yaml installation configuration file.

Procedure

  1. Change to the directory that contains the OpenShift Container Platform installation program and generate the Kubernetes manifests for the cluster:

    $ ./openshift-install create manifests --dir <installation_directory>

    where:

    <installation_directory>
    Specifies the installation directory that contains the install-config.yaml file you created.
  2. Remove the Kubernetes manifest files that define the control plane machines:

    $ rm -f <installation_directory>/openshift/99_openshift-cluster-api_master-machines-*.yaml

    By removing these files, you prevent the cluster from automatically generating control plane machines.

  3. Remove the Kubernetes manifest files that define the control plane machine set:

    $ rm -f <installation_directory>/openshift/99_openshift-machine-api_master-control-plane-machine-set.yaml
  4. Remove the Kubernetes manifest files that define the worker machines:

    $ rm -f <installation_directory>/openshift/99_openshift-cluster-api_worker-machineset-*.yaml
    Important

    If you disabled the MachineAPI capability when installing a cluster on user-provisioned infrastructure, you must remove the Kubernetes manifest files that define the worker machines. Otherwise, your cluster fails to install.

    Because you create and manage the worker machines yourself, you do not need to initialize these machines.

  5. Verify that the mastersSchedulable parameter in the <installation_directory>/manifests/cluster-scheduler-02-config.yml Kubernetes manifest file is set to false. This setting prevents pods from being scheduled on the control plane machines:

    1. Open the <installation_directory>/manifests/cluster-scheduler-02-config.yml file.
    2. Locate the mastersSchedulable parameter and verify that it is set to false.
    3. Save and exit the file.
  6. Optional: If you do not want the Ingress Operator to create DNS records on your behalf, remove the privateZone and publicZone sections from the <installation_directory>/manifests/cluster-dns-02-config.yml DNS configuration file:

    apiVersion: config.openshift.io/v1
    kind: DNS
    metadata:
      creationTimestamp: null
      name: cluster
    spec:
      baseDomain: example.openshift.com
      privateZone:
        id: mycluster-100419-private-zone
      publicZone:
        id: example.openshift.com
    status: {}

    spec.privateZone: Remove this section completely.

    If you do so, you must add ingress DNS records manually in a later step.

  7. To create the Ignition configuration files, run the following command from the directory that contains the installation program:

    $ ./openshift-install create ignition-configs --dir <installation_directory>

    where:

    <installation_directory>

    Specifies the same installation directory.

    The installation program creates Ignition config files for the bootstrap, control plane, and compute nodes in the installation directory. The program also creates the kubeadmin-password and kubeconfig files in the ./<installation_directory>/auth directory:

    .
    ├── auth
    │   ├── kubeadmin-password
    │   └── kubeconfig
    ├── bootstrap.ign
    ├── master.ign
    ├── metadata.json
    └── worker.ign

4.4.4. Extracting the infrastructure name

To identify your cluster resources in Amazon Web Services, extract the unique infrastructure name from the Ignition config files.

The Ignition config files contain a unique cluster identifier that you can use to uniquely identify your cluster in Amazon Web Services. The infrastructure name is also used to locate the appropriate AWS resources during an OpenShift Container Platform installation. The provided CloudFormation templates contain references to this infrastructure name, so you must extract it.

Prerequisites

  • You obtained the OpenShift Container Platform installation program and the pull secret for your cluster.
  • You generated the Ignition config files for your cluster.
  • You installed the jq package.

Procedure

  • To extract and view the infrastructure name from the Ignition config file metadata, run the following command:

    $ jq -r .infraID <installation_directory>/metadata.json

    where <installation_directory> is the path to the directory that you stored the installation files in.

    Example output

    openshift-vw9j6

    The output of this command is your cluster name and a random string.

4.4.5. Creating a VPC in AWS

To provide the network foundation for your OpenShift Container Platform cluster, create a Virtual Private Cloud (VPC) in Amazon Web Services (AWS) by using the provided CloudFormation template.

You can customize the VPC to meet your requirements, including VPN and route tables. You can use the provided CloudFormation template and a custom parameter file to create a stack of AWS resources that represent the VPC.

Note

If you do not use the provided CloudFormation template to create your AWS infrastructure, you must review the provided information and manually create the infrastructure. If your cluster does not initialize correctly, you might have to contact Red Hat support with your installation logs.

Prerequisites

  • You added your AWS keys and region to your local AWS profile by running aws configure.

Procedure

  1. Create a JSON file that contains the parameter values that the template requires:

    [
      {
        "ParameterKey": "VpcCidr",
        "ParameterValue": "10.0.0.0/16"
      },
      {
        "ParameterKey": "AvailabilityZoneCount",
        "ParameterValue": "1"
      },
      {
        "ParameterKey": "SubnetBits",
        "ParameterValue": "12"
      }
    ]

    where:

    VpcCidr
    Specifies the CIDR block for the VPC in the format x.x.x.x/16-24.
    AvailabilityZoneCount
    Specifies the number of availability zones to deploy the VPC in. Set the value to an integer between 1 and 3.
    SubnetBits
    Specifies the size of each subnet in each availability zone. Set the value to an integer between 5 and 13, where 5 is /27 and 13 is /19.
  2. Copy the template from the CloudFormation template for the VPC section of this topic and save it as a YAML file on your computer. This template describes the VPC that your cluster requires.
  3. Launch the CloudFormation template to create a stack of AWS resources that represent the VPC:

    Important

    You must enter the command on a single line.

    $ aws cloudformation create-stack --stack-name <name> \
         --template-body file://<template>.yaml \
         --parameters file://<parameters>.json

    where:

    <name>
    Specifies the name for the CloudFormation stack, such as cluster-vpc. You need the name of this stack if you remove the cluster.
    <template>
    Specifies the relative path to and name of the CloudFormation template YAML file that you saved.
    <parameters>
    Specifies the relative path to and name of the CloudFormation parameters JSON file.

    Example output

    arn:aws:cloudformation:us-east-1:269333783861:stack/cluster-vpc/dbedae40-2fd3-11eb-820e-12a48460849f

  4. Confirm that the template components exist:

    $ aws cloudformation describe-stacks --stack-name <name>

    After the StackStatus displays CREATE_COMPLETE, the output displays values for the following parameters. You must provide these parameter values to the other CloudFormation templates that you run to create your cluster:

    VpcId

    The ID of your VPC.

    PublicSubnetIds

    The IDs of the new public subnets.

    PrivateSubnetIds

    The IDs of the new private subnets.

4.4.5.1. CloudFormation template for the VPC

The VPC CloudFormation template creates the Amazon Web Services (AWS) networking infrastructure, including the public and private subnets, that your OpenShift Container Platform cluster requires.

CloudFormation template for the VPC

AWSTemplateFormatVersion: 2010-09-09
Description: Template for Best Practice VPC with 1-3 AZs

Parameters:
  VpcCidr:
    AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-4]))$
    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-24.
    Default: 10.0.0.0/16
    Description: CIDR block for VPC.
    Type: String
  AvailabilityZoneCount:
    ConstraintDescription: "The number of availability zones. (Min: 1, Max: 3)"
    MinValue: 1
    MaxValue: 3
    Default: 1
    Description: "How many AZs to create VPC subnets for. (Min: 1, Max: 3)"
    Type: Number
  SubnetBits:
    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/19-27.
    MinValue: 5
    MaxValue: 13
    Default: 12
    Description: "Size of each subnet to create within the availability zones. (Min: 5 = /27, Max: 13 = /19)"
    Type: Number

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
    - Label:
        default: "Network Configuration"
      Parameters:
      - VpcCidr
      - SubnetBits
    - Label:
        default: "Availability Zones"
      Parameters:
      - AvailabilityZoneCount
    ParameterLabels:
      AvailabilityZoneCount:
        default: "Availability Zone Count"
      VpcCidr:
        default: "VPC CIDR"
      SubnetBits:
        default: "Bits Per Subnet"

Conditions:
  DoAz3: !Equals [3, !Ref AvailabilityZoneCount]
  DoAz2: !Or [!Equals [2, !Ref AvailabilityZoneCount], Condition: DoAz3]

Resources:
  VPC:
    Type: "AWS::EC2::VPC"
    Properties:
      EnableDnsSupport: "true"
      EnableDnsHostnames: "true"
      CidrBlock: !Ref VpcCidr
  PublicSubnet:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Select [0, !Cidr [!Ref VpcCidr, 6, !Ref SubnetBits]]
      AvailabilityZone: !Select
      - 0
      - Fn::GetAZs: !Ref "AWS::Region"
  PublicSubnet2:
    Type: "AWS::EC2::Subnet"
    Condition: DoAz2
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Select [1, !Cidr [!Ref VpcCidr, 6, !Ref SubnetBits]]
      AvailabilityZone: !Select
      - 1
      - Fn::GetAZs: !Ref "AWS::Region"
  PublicSubnet3:
    Type: "AWS::EC2::Subnet"
    Condition: DoAz3
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Select [2, !Cidr [!Ref VpcCidr, 6, !Ref SubnetBits]]
      AvailabilityZone: !Select
      - 2
      - Fn::GetAZs: !Ref "AWS::Region"
  InternetGateway:
    Type: "AWS::EC2::InternetGateway"
  GatewayToInternet:
    Type: "AWS::EC2::VPCGatewayAttachment"
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway
  PublicRouteTable:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: !Ref VPC
  PublicRoute:
    Type: "AWS::EC2::Route"
    DependsOn: GatewayToInternet
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway
  PublicSubnetRouteTableAssociation:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicRouteTable
  PublicSubnetRouteTableAssociation2:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Condition: DoAz2
    Properties:
      SubnetId: !Ref PublicSubnet2
      RouteTableId: !Ref PublicRouteTable
  PublicSubnetRouteTableAssociation3:
    Condition: DoAz3
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId: !Ref PublicSubnet3
      RouteTableId: !Ref PublicRouteTable
  PrivateSubnet:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Select [3, !Cidr [!Ref VpcCidr, 6, !Ref SubnetBits]]
      AvailabilityZone: !Select
      - 0
      - Fn::GetAZs: !Ref "AWS::Region"
  PrivateRouteTable:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: !Ref VPC
  PrivateSubnetRouteTableAssociation:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId: !Ref PrivateSubnet
      RouteTableId: !Ref PrivateRouteTable
  NAT:
    DependsOn:
    - GatewayToInternet
    Type: "AWS::EC2::NatGateway"
    Properties:
      AllocationId:
        "Fn::GetAtt":
        - EIP
        - AllocationId
      SubnetId: !Ref PublicSubnet
  EIP:
    Type: "AWS::EC2::EIP"
    Properties:
      Domain: vpc
  Route:
    Type: "AWS::EC2::Route"
    Properties:
      RouteTableId:
        Ref: PrivateRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId:
        Ref: NAT
  PrivateSubnet2:
    Type: "AWS::EC2::Subnet"
    Condition: DoAz2
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Select [4, !Cidr [!Ref VpcCidr, 6, !Ref SubnetBits]]
      AvailabilityZone: !Select
      - 1
      - Fn::GetAZs: !Ref "AWS::Region"
  PrivateRouteTable2:
    Type: "AWS::EC2::RouteTable"
    Condition: DoAz2
    Properties:
      VpcId: !Ref VPC
  PrivateSubnetRouteTableAssociation2:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Condition: DoAz2
    Properties:
      SubnetId: !Ref PrivateSubnet2
      RouteTableId: !Ref PrivateRouteTable2
  NAT2:
    DependsOn:
    - GatewayToInternet
    Type: "AWS::EC2::NatGateway"
    Condition: DoAz2
    Properties:
      AllocationId:
        "Fn::GetAtt":
        - EIP2
        - AllocationId
      SubnetId: !Ref PublicSubnet2
  EIP2:
    Type: "AWS::EC2::EIP"
    Condition: DoAz2
    Properties:
      Domain: vpc
  Route2:
    Type: "AWS::EC2::Route"
    Condition: DoAz2
    Properties:
      RouteTableId:
        Ref: PrivateRouteTable2
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId:
        Ref: NAT2
  PrivateSubnet3:
    Type: "AWS::EC2::Subnet"
    Condition: DoAz3
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Select [5, !Cidr [!Ref VpcCidr, 6, !Ref SubnetBits]]
      AvailabilityZone: !Select
      - 2
      - Fn::GetAZs: !Ref "AWS::Region"
  PrivateRouteTable3:
    Type: "AWS::EC2::RouteTable"
    Condition: DoAz3
    Properties:
      VpcId: !Ref VPC
  PrivateSubnetRouteTableAssociation3:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Condition: DoAz3
    Properties:
      SubnetId: !Ref PrivateSubnet3
      RouteTableId: !Ref PrivateRouteTable3
  NAT3:
    DependsOn:
    - GatewayToInternet
    Type: "AWS::EC2::NatGateway"
    Condition: DoAz3
    Properties:
      AllocationId:
        "Fn::GetAtt":
        - EIP3
        - AllocationId
      SubnetId: !Ref PublicSubnet3
  EIP3:
    Type: "AWS::EC2::EIP"
    Condition: DoAz3
    Properties:
      Domain: vpc
  Route3:
    Type: "AWS::EC2::Route"
    Condition: DoAz3
    Properties:
      RouteTableId:
        Ref: PrivateRouteTable3
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId:
        Ref: NAT3
  S3Endpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Principal: '*'
          Action:
          - '*'
          Resource:
          - '*'
      RouteTableIds:
      - !Ref PublicRouteTable
      - !Ref PrivateRouteTable
      - !If [DoAz2, !Ref PrivateRouteTable2, !Ref "AWS::NoValue"]
      - !If [DoAz3, !Ref PrivateRouteTable3, !Ref "AWS::NoValue"]
      ServiceName: !Join
      - ''
      - - com.amazonaws.
        - !Ref 'AWS::Region'
        - .s3
      VpcId: !Ref VPC

Outputs:
  VpcId:
    Description: ID of the new VPC.
    Value: !Ref VPC
  PublicSubnetIds:
    Description: Subnet IDs of the public subnets.
    Value:
      !Join [
        ",",
        [!Ref PublicSubnet, !If [DoAz2, !Ref PublicSubnet2, !Ref "AWS::NoValue"], !If [DoAz3, !Ref PublicSubnet3, !Ref "AWS::NoValue"]]
      ]
  PrivateSubnetIds:
    Description: Subnet IDs of the private subnets.
    Value:
      !Join [
        ",",
        [!Ref PrivateSubnet, !If [DoAz2, !Ref PrivateSubnet2, !Ref "AWS::NoValue"], !If [DoAz3, !Ref PrivateSubnet3, !Ref "AWS::NoValue"]]
      ]
  PublicRouteTableId:
    Description: Public Route table ID
    Value: !Ref PublicRouteTable
  PrivateRouteTableIds:
    Description: Private Route table IDs
    Value:
      !Join [
        ",",
        [
          !Join ["=", [
            !Select [0, "Fn::GetAZs": !Ref "AWS::Region"],
            !Ref PrivateRouteTable
          ]],
          !If [DoAz2,
               !Join ["=", [!Select [1, "Fn::GetAZs": !Ref "AWS::Region"], !Ref PrivateRouteTable2]],
               !Ref "AWS::NoValue"
          ],
          !If [DoAz3,
               !Join ["=", [!Select [2, "Fn::GetAZs": !Ref "AWS::Region"], !Ref PrivateRouteTable3]],
               !Ref "AWS::NoValue"
          ]
        ]
      ]

4.4.6. Creating networking and load balancing components in AWS

To route traffic to your OpenShift Container Platform cluster, configure the networking and load balancing components in Amazon Web Services (AWS) by using the provided CloudFormation template.

You can use the provided CloudFormation template and a custom parameter file to create a stack of AWS resources. The stack represents the networking and load balancing components that your OpenShift Container Platform cluster requires. The template also creates a hosted zone and subnet tags.

You can run the template many times within a single Virtual Private Cloud (VPC).

Note

If you do not use the provided CloudFormation template to create your AWS infrastructure, you must review the provided information and manually create the infrastructure. If your cluster does not initialize correctly, you might have to contact Red Hat support with your installation logs.

Prerequisites

  • You created and configured a VPC and associated subnets in AWS.

Procedure

  1. Obtain the hosted zone ID for the Route 53 base domain that you specified in the install-config.yaml file for your cluster. You can obtain details about your hosted zone by running the following command:

    $ aws route53 list-hosted-zones-by-name --dns-name <route53_domain>

    where <route53_domain> is the Route 53 base domain that you used when you generated the install-config.yaml file for the cluster.

    Example output

    mycluster.example.com.	False	100
    HOSTEDZONES	65F8F38E-2268-B835-E15C-AB55336FCBFA	/hostedzone/Z21IXYZABCZ2A4	mycluster.example.com.	10

    In the example output, the hosted zone ID is Z21IXYZABCZ2A4.

  2. Create a JSON file that has the parameter values that the template requires:

    [
      {
        "ParameterKey": "ClusterName",
        "ParameterValue": "mycluster"
      },
      {
        "ParameterKey": "InfrastructureName",
        "ParameterValue": "mycluster-<random_string>"
      },
      {
        "ParameterKey": "HostedZoneId",
        "ParameterValue": "<random_string>"
      },
      {
        "ParameterKey": "HostedZoneName",
        "ParameterValue": "example.com"
      },
      {
        "ParameterKey": "PublicSubnets",
        "ParameterValue": "subnet-<random_string>"
      },
      {
        "ParameterKey": "PrivateSubnets",
        "ParameterValue": "subnet-<random_string>"
      },
      {
        "ParameterKey": "VpcId",
        "ParameterValue": "vpc-<random_string>"
      }
    ]

    where:

    ClusterName
    Specifies a short, representative cluster name to use for hostnames, and so on. Set the value to the cluster name that you used when you generated the install-config.yaml file for the cluster.
    InfrastructureName
    Specifies the name for your cluster infrastructure that your Ignition config files encode for the cluster. Set the value to the infrastructure name that you extracted from the Ignition config file metadata, which has the format <cluster_name>-<random_string>.
    HostedZoneId
    Specifies the Route 53 public zone ID to register the targets with. Set the value to the Route 53 public zone ID, which has a format similar to Z21IXYZABCZ2A4. You can obtain this value from the AWS console.
    HostedZoneName
    Specifies the Route 53 zone to register the targets with. Set the value to the Route 53 base domain that you used when you generated the install-config.yaml file for the cluster. Do not include the trailing period (.) that is displayed in the AWS console.
    PublicSubnets
    Specifies the public subnets that you created for your VPC. Set the value to the PublicSubnetIds value from the output of the CloudFormation template for the VPC.
    PrivateSubnets
    Specifies the private subnets that you created for your VPC. Set the value to the PrivateSubnetIds value from the output of the CloudFormation template for the VPC.
    VpcId
    Specifies the VPC that you created for the cluster. Set the value to the VpcId value from the output of the CloudFormation template for the VPC.
  3. Copy the template from the CloudFormation template for the network and load balancers section and save it as a YAML file on your computer. This template describes the networking and load balancing objects that your cluster requires.

    Important

    If you are deploying your cluster to an AWS government or secret region, you must update the InternalApiServerRecord in the CloudFormation template to use CNAME records. Records of type ALIAS are not supported for AWS government regions.

  4. Launch the CloudFormation template to create a stack of AWS resources for the networking and load balancing components:

    Important

    You must enter the command on a single line.

    $ aws cloudformation create-stack --stack-name <name> \
         --template-body file://<template>.yaml \
         --parameters file://<parameters>.json \
         --capabilities CAPABILITY_NAMED_IAM

    where:

    <name>
    Specifies the name for the CloudFormation stack, such as cluster-dns. You need the name of this stack if you remove the cluster.
    <template>
    Specifies the relative path to and name of the CloudFormation template YAML file that you saved.
    <parameters>
    Specifies the relative path to and name of the CloudFormation parameters JSON file.
    CAPABILITY_NAMED_IAM
    You must explicitly declare this capability because the provided template creates some AWS::IAM::Role resources.

    Example output

    arn:aws:cloudformation:us-east-1:269333783861:stack/cluster-dns/cd3e5de0-2fd4-11eb-5cf0-12be5c33a183

  5. Confirm that the template components exist:

    $ aws cloudformation describe-stacks --stack-name <name>

    After the StackStatus displays CREATE_COMPLETE, the output displays values for the following parameters. You must give these parameter values to the other CloudFormation templates that you run to create your cluster:

    PrivateHostedZoneId

    Hosted zone ID for the private DNS.

    ExternalApiLoadBalancerName

    Full name of the external API load balancer.

    InternalApiLoadBalancerName

    Full name of the internal API load balancer.

    ApiServerDnsName

    Full hostname of the API server.

    RegisterNlbIpTargetsLambda

    Lambda ARN useful to help register and unregister IP targets for these load balancers.

    ExternalApiTargetGroupArn

    ARN of external API target group.

    InternalApiTargetGroupArn

    ARN of internal API target group.

    InternalServiceTargetGroupArn

    ARN of internal service target group.

4.4.6.1. CloudFormation template for the network and load balancers

The networking CloudFormation template creates the Route 53 DNS entries and load balancers on Amazon Web Services (AWS) that route traffic to your OpenShift Container Platform control plane and applications.

CloudFormation template for the network and load balancers

AWSTemplateFormatVersion: 2010-09-09
Description: Template for OpenShift Cluster Network Elements (Route53 & LBs)

Parameters:
  ClusterName:
    AllowedPattern: ^([a-zA-Z][a-zA-Z0-9\-]{0,26})$
    MaxLength: 27
    MinLength: 1
    ConstraintDescription: Cluster name must be alphanumeric, start with a letter, and have a maximum of 27 characters.
    Description: A short, representative cluster name to use for host names and other identifying names.
    Type: String
  InfrastructureName:
    AllowedPattern: ^([a-zA-Z][a-zA-Z0-9\-]{0,26})$
    MaxLength: 27
    MinLength: 1
    ConstraintDescription: Infrastructure name must be alphanumeric, start with a letter, and have a maximum of 27 characters.
    Description: A short, unique cluster ID used to tag cloud resources and identify items owned or used by the cluster.
    Type: String
  HostedZoneId:
    Description: The Route53 public zone ID to register the targets with, such as Z21IXYZABCZ2A4.
    Type: String
  HostedZoneName:
    Description: The Route53 zone to register the targets with, such as example.com. Omit the trailing period.
    Type: String
    Default: "example.com"
  PublicSubnets:
    Description: The internet-facing subnets.
    Type: List<AWS::EC2::Subnet::Id>
  PrivateSubnets:
    Description: The internal subnets.
    Type: List<AWS::EC2::Subnet::Id>
  VpcId:
    Description: The VPC-scoped resources will belong to this VPC.
    Type: AWS::EC2::VPC::Id

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
    - Label:
        default: "Cluster Information"
      Parameters:
      - ClusterName
      - InfrastructureName
    - Label:
        default: "Network Configuration"
      Parameters:
      - VpcId
      - PublicSubnets
      - PrivateSubnets
    - Label:
        default: "DNS"
      Parameters:
      - HostedZoneName
      - HostedZoneId
    ParameterLabels:
      ClusterName:
        default: "Cluster Name"
      InfrastructureName:
        default: "Infrastructure Name"
      VpcId:
        default: "VPC ID"
      PublicSubnets:
        default: "Public Subnets"
      PrivateSubnets:
        default: "Private Subnets"
      HostedZoneName:
        default: "Public Hosted Zone Name"
      HostedZoneId:
        default: "Public Hosted Zone ID"

Resources:
  ExtApiElb:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: !Join ["-", [!Ref InfrastructureName, "ext"]]
      IpAddressType: ipv4
      Subnets: !Ref PublicSubnets
      Type: network

  IntApiElb:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: !Join ["-", [!Ref InfrastructureName, "int"]]
      Scheme: internal
      IpAddressType: ipv4
      Subnets: !Ref PrivateSubnets
      Type: network

  IntDns:
    Type: "AWS::Route53::HostedZone"
    Properties:
      HostedZoneConfig:
        Comment: "Managed by CloudFormation"
      Name: !Join [".", [!Ref ClusterName, !Ref HostedZoneName]]
      HostedZoneTags:
      - Key: Name
        Value: !Join ["-", [!Ref InfrastructureName, "int"]]
      - Key: !Join ["", ["kubernetes.io/cluster/", !Ref InfrastructureName]]
        Value: "owned"
      VPCs:
      - VPCId: !Ref VpcId
        VPCRegion: !Ref "AWS::Region"

  ExternalApiServerRecord:
    Type: AWS::Route53::RecordSetGroup
    Properties:
      Comment: Alias record for the API server
      HostedZoneId: !Ref HostedZoneId
      RecordSets:
      - Name:
          !Join [
            ".",
            ["api", !Ref ClusterName, !Join ["", [!Ref HostedZoneName, "."]]],
          ]
        Type: A
        AliasTarget:
          HostedZoneId: !GetAtt ExtApiElb.CanonicalHostedZoneID
          DNSName: !GetAtt ExtApiElb.DNSName

  InternalApiServerRecord:
    Type: AWS::Route53::RecordSetGroup
    Properties:
      Comment: Alias record for the API server
      HostedZoneId: !Ref IntDns
      RecordSets:
      - Name:
          !Join [
            ".",
            ["api", !Ref ClusterName, !Join ["", [!Ref HostedZoneName, "."]]],
          ]
        Type: A
        AliasTarget:
          HostedZoneId: !GetAtt IntApiElb.CanonicalHostedZoneID
          DNSName: !GetAtt IntApiElb.DNSName
      - Name:
          !Join [
            ".",
            ["api-int", !Ref ClusterName, !Join ["", [!Ref HostedZoneName, "."]]],
          ]
        Type: A
        AliasTarget:
          HostedZoneId: !GetAtt IntApiElb.CanonicalHostedZoneID
          DNSName: !GetAtt IntApiElb.DNSName

  ExternalApiListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
      - Type: forward
        TargetGroupArn:
          Ref: ExternalApiTargetGroup
      LoadBalancerArn:
        Ref: ExtApiElb
      Port: 6443
      Protocol: TCP

  ExternalApiTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckIntervalSeconds: 10
      HealthCheckPath: "/readyz"
      HealthCheckPort: 6443
      HealthCheckProtocol: HTTPS
      HealthyThresholdCount: 2
      UnhealthyThresholdCount: 2
      Port: 6443
      Protocol: TCP
      TargetType: ip
      VpcId:
        Ref: VpcId
      TargetGroupAttributes:
      - Key: deregistration_delay.timeout_seconds
        Value: 60

  InternalApiListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
      - Type: forward
        TargetGroupArn:
          Ref: InternalApiTargetGroup
      LoadBalancerArn:
        Ref: IntApiElb
      Port: 6443
      Protocol: TCP

  InternalApiTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckIntervalSeconds: 10
      HealthCheckPath: "/readyz"
      HealthCheckPort: 6443
      HealthCheckProtocol: HTTPS
      HealthyThresholdCount: 2
      UnhealthyThresholdCount: 2
      Port: 6443
      Protocol: TCP
      TargetType: ip
      VpcId:
        Ref: VpcId
      TargetGroupAttributes:
      - Key: deregistration_delay.timeout_seconds
        Value: 60

  InternalServiceInternalListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
      - Type: forward
        TargetGroupArn:
          Ref: InternalServiceTargetGroup
      LoadBalancerArn:
        Ref: IntApiElb
      Port: 22623
      Protocol: TCP

  InternalServiceTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckIntervalSeconds: 10
      HealthCheckPath: "/healthz"
      HealthCheckPort: 22623
      HealthCheckProtocol: HTTPS
      HealthyThresholdCount: 2
      UnhealthyThresholdCount: 2
      Port: 22623
      Protocol: TCP
      TargetType: ip
      VpcId:
        Ref: VpcId
      TargetGroupAttributes:
      - Key: deregistration_delay.timeout_seconds
        Value: 60

  RegisterTargetLambdaIamRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Join ["-", [!Ref InfrastructureName, "nlb", "lambda", "role"]]
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
        - Effect: "Allow"
          Principal:
            Service:
            - "lambda.amazonaws.com"
          Action:
          - "sts:AssumeRole"
      Path: "/"
      Policies:
      - PolicyName: !Join ["-", [!Ref InfrastructureName, "master", "policy"]]
        PolicyDocument:
          Version: "2012-10-17"
          Statement:
          - Effect: "Allow"
            Action:
              [
                "elasticloadbalancing:RegisterTargets",
                "elasticloadbalancing:DeregisterTargets",
              ]
            Resource: !Ref InternalApiTargetGroup
          - Effect: "Allow"
            Action:
              [
                "elasticloadbalancing:RegisterTargets",
                "elasticloadbalancing:DeregisterTargets",
              ]
            Resource: !Ref InternalServiceTargetGroup
          - Effect: "Allow"
            Action:
              [
                "elasticloadbalancing:RegisterTargets",
                "elasticloadbalancing:DeregisterTargets",
              ]
            Resource: !Ref ExternalApiTargetGroup

  RegisterNlbIpTargets:
    Type: "AWS::Lambda::Function"
    Properties:
      Handler: "index.handler"
      Role:
        Fn::GetAtt:
        - "RegisterTargetLambdaIamRole"
        - "Arn"
      Code:
        ZipFile: |
          import json
          import boto3
          import cfnresponse
          def handler(event, context):
            elb = boto3.client('elbv2')
            if event['RequestType'] == 'Delete':
              elb.deregister_targets(TargetGroupArn=event['ResourceProperties']['TargetArn'],Targets=[{'Id': event['ResourceProperties']['TargetIp']}])
            elif event['RequestType'] == 'Create':
              elb.register_targets(TargetGroupArn=event['ResourceProperties']['TargetArn'],Targets=[{'Id': event['ResourceProperties']['TargetIp']}])
            responseData = {}
            cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, event['ResourceProperties']['TargetArn']+event['ResourceProperties']['TargetIp'])
      Runtime: "python3.11"
      Timeout: 120

  RegisterSubnetTagsLambdaIamRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Join ["-", [!Ref InfrastructureName, "subnet-tags-lambda-role"]]
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
        - Effect: "Allow"
          Principal:
            Service:
            - "lambda.amazonaws.com"
          Action:
          - "sts:AssumeRole"
      Path: "/"
      Policies:
      - PolicyName: !Join ["-", [!Ref InfrastructureName, "subnet-tagging-policy"]]
        PolicyDocument:
          Version: "2012-10-17"
          Statement:
          - Effect: "Allow"
            Action:
              [
                "ec2:DeleteTags",
                "ec2:CreateTags"
              ]
            Resource: "arn:aws:ec2:*:*:subnet/*"
          - Effect: "Allow"
            Action:
              [
                "ec2:DescribeSubnets",
                "ec2:DescribeTags"
              ]
            Resource: "*"

  RegisterSubnetTags:
    Type: "AWS::Lambda::Function"
    Properties:
      Handler: "index.handler"
      Role:
        Fn::GetAtt:
        - "RegisterSubnetTagsLambdaIamRole"
        - "Arn"
      Code:
        ZipFile: |
          import json
          import boto3
          import cfnresponse
          def handler(event, context):
            ec2_client = boto3.client('ec2')
            if event['RequestType'] == 'Delete':
              for subnet_id in event['ResourceProperties']['Subnets']:
                ec2_client.delete_tags(Resources=[subnet_id], Tags=[{'Key': 'kubernetes.io/cluster/' + event['ResourceProperties']['InfrastructureName']}]);
            elif event['RequestType'] == 'Create':
              for subnet_id in event['ResourceProperties']['Subnets']:
                ec2_client.create_tags(Resources=[subnet_id], Tags=[{'Key': 'kubernetes.io/cluster/' + event['ResourceProperties']['InfrastructureName'], 'Value': 'shared'}]);
            responseData = {}
            cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, event['ResourceProperties']['InfrastructureName']+event['ResourceProperties']['Subnets'][0])
      Runtime: "python3.11"
      Timeout: 120

  RegisterPublicSubnetTags:
    Type: Custom::SubnetRegister
    Properties:
      ServiceToken: !GetAtt RegisterSubnetTags.Arn
      InfrastructureName: !Ref InfrastructureName
      Subnets: !Ref PublicSubnets

  RegisterPrivateSubnetTags:
    Type: Custom::SubnetRegister
    Properties:
      ServiceToken: !GetAtt RegisterSubnetTags.Arn
      InfrastructureName: !Ref InfrastructureName
      Subnets: !Ref PrivateSubnets

Outputs:
  PrivateHostedZoneId:
    Description: Hosted zone ID for the private DNS, which is required for private records.
    Value: !Ref IntDns
  ExternalApiLoadBalancerName:
    Description: Full name of the external API load balancer.
    Value: !GetAtt ExtApiElb.LoadBalancerFullName
  InternalApiLoadBalancerName:
    Description: Full name of the internal API load balancer.
    Value: !GetAtt IntApiElb.LoadBalancerFullName
  ApiServerDnsName:
    Description: Full hostname of the API server, which is required for the Ignition config files.
    Value: !Join [".", ["api-int", !Ref ClusterName, !Ref HostedZoneName]]
  RegisterNlbIpTargetsLambda:
    Description: Lambda ARN useful to help register or deregister IP targets for these load balancers.
    Value: !GetAtt RegisterNlbIpTargets.Arn
  ExternalApiTargetGroupArn:
    Description: ARN of the external API target group.
    Value: !Ref ExternalApiTargetGroup
  InternalApiTargetGroupArn:
    Description: ARN of the internal API target group.
    Value: !Ref InternalApiTargetGroup
  InternalServiceTargetGroupArn:
    Description: ARN of the internal service target group.
    Value: !Ref InternalServiceTargetGroup

Important

If you are deploying your cluster to an AWS government or secret region, you must update the InternalApiServerRecord to use CNAME records. Records of type ALIAS are not supported for AWS government regions. For example:

Type: CNAME
TTL: 10
ResourceRecords:
- !GetAtt IntApiElb.DNSName

4.4.7. Creating security group and roles in AWS

To control access to your OpenShift Container Platform cluster resources, create the required security groups and IAM roles in Amazon Web Services (AWS) by using the provided CloudFormation template.

You can use the provided CloudFormation template and a custom parameter file to create a stack of AWS resources. The stack represents the security groups and roles that your OpenShift Container Platform cluster requires.

Note

If you do not use the provided CloudFormation template to create your AWS infrastructure, you must review the provided information and manually create the infrastructure. If your cluster does not initialize correctly, you might have to contact Red Hat support with your installation logs.

Procedure

  1. Create a JSON file that has the parameter values that the template requires:

    [
      {
        "ParameterKey": "InfrastructureName",
        "ParameterValue": "mycluster-<random_string>"
      },
      {
        "ParameterKey": "VpcCidr",
        "ParameterValue": "10.0.0.0/16"
      },
      {
        "ParameterKey": "PrivateSubnets",
        "ParameterValue": "subnet-<random_string>"
      },
      {
        "ParameterKey": "VpcId",
        "ParameterValue": "vpc-<random_string>"
      }
    ]

    where:

    InfrastructureName
    Specifies the name for your cluster infrastructure that your Ignition config files encode for the cluster. Set the value to the infrastructure name that you extracted from the Ignition config file metadata, which has the format <cluster_name>-<random_string>.
    VpcCidr
    Specifies the CIDR block for the VPC. Set the value to the CIDR block parameter that you used for the VPC that you defined in the form x.x.x.x/16-24.
    PrivateSubnets
    Specifies the private subnets that you created for your VPC. Set the value to the PrivateSubnetIds value from the output of the CloudFormation template for the VPC.
    VpcId
    Specifies the VPC that you created for the cluster. Set the value to the VpcId value from the output of the CloudFormation template for the VPC.
  2. Copy the template from the CloudFormation template for security objects section and save it as a YAML file on your computer. This template describes the security groups and roles that your cluster requires.
  3. Launch the CloudFormation template to create a stack of AWS resources that represent the security groups and roles:

    Important

    You must enter the command on a single line.

    $ aws cloudformation create-stack --stack-name <name> \
         --template-body file://<template>.yaml \
         --parameters file://<parameters>.json \
         --capabilities CAPABILITY_NAMED_IAM

    where:

    <name>
    Specifies the name for the CloudFormation stack, such as cluster-sec. You need the name of this stack if you remove the cluster.
    <template>
    Specifies the relative path to and name of the CloudFormation template YAML file that you saved.
    <parameters>
    Specifies the relative path to and name of the CloudFormation parameters JSON file.
    CAPABILITY_NAMED_IAM
    You must explicitly declare this capability because the provided template creates some AWS::IAM::Role and AWS::IAM::InstanceProfile resources.

    Example output

    arn:aws:cloudformation:us-east-1:269333783861:stack/cluster-sec/03bd4210-2ed7-11eb-6d7a-13fc0b61e9db

  4. Confirm that the template components exist:

    $ aws cloudformation describe-stacks --stack-name <name>

    After the StackStatus displays CREATE_COMPLETE, the output displays values for the following parameters. You must give these parameter values to the other CloudFormation templates that you run to create your cluster:

    MasterSecurityGroupId

    Control plane security group ID

    WorkerSecurityGroupId

    Worker security group ID

    MasterInstanceProfile

    Control plane IAM instance profile

    WorkerInstanceProfile

    Worker IAM instance profile

4.4.7.1. CloudFormation template for security objects

The security CloudFormation template creates the IAM roles and security groups on Amazon Web Services (AWS) that control access to your OpenShift Container Platform cluster resources.

CloudFormation template for security objects

AWSTemplateFormatVersion: 2010-09-09
Description: Template for OpenShift Cluster Security Elements (Security Groups & IAM)

Parameters:
  InfrastructureName:
    AllowedPattern: ^([a-zA-Z][a-zA-Z0-9\-]{0,26})$
    MaxLength: 27
    MinLength: 1
    ConstraintDescription: Infrastructure name must be alphanumeric, start with a letter, and have a maximum of 27 characters.
    Description: A short, unique cluster ID used to tag cloud resources and identify items owned or used by the cluster.
    Type: String
  VpcCidr:
    AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-4]))$
    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-24.
    Default: 10.0.0.0/16
    Description: CIDR block for VPC.
    Type: String
  VpcId:
    Description: The VPC-scoped resources will belong to this VPC.
    Type: AWS::EC2::VPC::Id
  PrivateSubnets:
    Description: The internal subnets.
    Type: List<AWS::EC2::Subnet::Id>

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
    - Label:
        default: "Cluster Information"
      Parameters:
      - InfrastructureName
    - Label:
        default: "Network Configuration"
      Parameters:
      - VpcId
      - VpcCidr
      - PrivateSubnets
    ParameterLabels:
      InfrastructureName:
        default: "Infrastructure Name"
      VpcId:
        default: "VPC ID"
      VpcCidr:
        default: "VPC CIDR"
      PrivateSubnets:
        default: "Private Subnets"

Resources:
  MasterSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Cluster Master Security Group
      SecurityGroupIngress:
      - IpProtocol: icmp
        FromPort: 0
        ToPort: 0
        CidrIp: !Ref VpcCidr
      - IpProtocol: tcp
        FromPort: 22
        ToPort: 22
        CidrIp: !Ref VpcCidr
      - IpProtocol: tcp
        ToPort: 6443
        FromPort: 6443
        CidrIp: !Ref VpcCidr
      - IpProtocol: tcp
        FromPort: 22623
        ToPort: 22623
        CidrIp: !Ref VpcCidr
      VpcId: !Ref VpcId

  WorkerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Cluster Worker Security Group
      SecurityGroupIngress:
      - IpProtocol: icmp
        FromPort: 0
        ToPort: 0
        CidrIp: !Ref VpcCidr
      - IpProtocol: tcp
        FromPort: 22
        ToPort: 22
        CidrIp: !Ref VpcCidr
      VpcId: !Ref VpcId

  MasterIngressEtcd:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: etcd
      FromPort: 2379
      ToPort: 2380
      IpProtocol: tcp

  MasterIngressVxlan:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Vxlan packets
      FromPort: 4789
      ToPort: 4789
      IpProtocol: udp

  MasterIngressWorkerVxlan:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Vxlan packets
      FromPort: 4789
      ToPort: 4789
      IpProtocol: udp

  MasterIngressGeneve:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Geneve packets
      FromPort: 6081
      ToPort: 6081
      IpProtocol: udp

  MasterIngressWorkerGeneve:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Geneve packets
      FromPort: 6081
      ToPort: 6081
      IpProtocol: udp

  MasterIngressIpsecIke:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: IPsec IKE packets
      FromPort: 500
      ToPort: 500
      IpProtocol: udp

  MasterIngressIpsecNat:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: IPsec NAT-T packets
      FromPort: 4500
      ToPort: 4500
      IpProtocol: udp

  MasterIngressIpsecEsp:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: IPsec ESP packets
      IpProtocol: 50

  MasterIngressWorkerIpsecIke:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: IPsec IKE packets
      FromPort: 500
      ToPort: 500
      IpProtocol: udp

  MasterIngressWorkerIpsecNat:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: IPsec NAT-T packets
      FromPort: 4500
      ToPort: 4500
      IpProtocol: udp

  MasterIngressWorkerIpsecEsp:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: IPsec ESP packets
      IpProtocol: 50

  MasterIngressInternal:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Internal cluster communication
      FromPort: 9000
      ToPort: 9999
      IpProtocol: tcp

  MasterIngressWorkerInternal:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Internal cluster communication
      FromPort: 9000
      ToPort: 9999
      IpProtocol: tcp

  MasterIngressInternalUDP:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Internal cluster communication
      FromPort: 9000
      ToPort: 9999
      IpProtocol: udp

  MasterIngressWorkerInternalUDP:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Internal cluster communication
      FromPort: 9000
      ToPort: 9999
      IpProtocol: udp

  MasterIngressKube:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Kubernetes kubelet, scheduler and controller manager
      FromPort: 10250
      ToPort: 10259
      IpProtocol: tcp

  MasterIngressWorkerKube:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Kubernetes kubelet, scheduler and controller manager
      FromPort: 10250
      ToPort: 10259
      IpProtocol: tcp

  MasterIngressIngressServices:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Kubernetes ingress services
      FromPort: 30000
      ToPort: 32767
      IpProtocol: tcp

  MasterIngressWorkerIngressServices:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Kubernetes ingress services
      FromPort: 30000
      ToPort: 32767
      IpProtocol: tcp

  MasterIngressIngressServicesUDP:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Kubernetes ingress services
      FromPort: 30000
      ToPort: 32767
      IpProtocol: udp

  MasterIngressWorkerIngressServicesUDP:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt MasterSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Kubernetes ingress services
      FromPort: 30000
      ToPort: 32767
      IpProtocol: udp

  WorkerIngressVxlan:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Vxlan packets
      FromPort: 4789
      ToPort: 4789
      IpProtocol: udp

  WorkerIngressMasterVxlan:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Vxlan packets
      FromPort: 4789
      ToPort: 4789
      IpProtocol: udp

  WorkerIngressGeneve:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Geneve packets
      FromPort: 6081
      ToPort: 6081
      IpProtocol: udp

  WorkerIngressMasterGeneve:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Geneve packets
      FromPort: 6081
      ToPort: 6081
      IpProtocol: udp

  WorkerIngressIpsecIke:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: IPsec IKE packets
      FromPort: 500
      ToPort: 500
      IpProtocol: udp

  WorkerIngressIpsecNat:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: IPsec NAT-T packets
      FromPort: 4500
      ToPort: 4500
      IpProtocol: udp

  WorkerIngressIpsecEsp:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: IPsec ESP packets
      IpProtocol: 50

  WorkerIngressMasterIpsecIke:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: IPsec IKE packets
      FromPort: 500
      ToPort: 500
      IpProtocol: udp

  WorkerIngressMasterIpsecNat:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: IPsec NAT-T packets
      FromPort: 4500
      ToPort: 4500
      IpProtocol: udp

  WorkerIngressMasterIpsecEsp:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: IPsec ESP packets
      IpProtocol: 50

  WorkerIngressInternal:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Internal cluster communication
      FromPort: 9000
      ToPort: 9999
      IpProtocol: tcp

  WorkerIngressMasterInternal:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Internal cluster communication
      FromPort: 9000
      ToPort: 9999
      IpProtocol: tcp

  WorkerIngressInternalUDP:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Internal cluster communication
      FromPort: 9000
      ToPort: 9999
      IpProtocol: udp

  WorkerIngressMasterInternalUDP:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Internal cluster communication
      FromPort: 9000
      ToPort: 9999
      IpProtocol: udp

  WorkerIngressKube:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Kubernetes secure kubelet port
      FromPort: 10250
      ToPort: 10250
      IpProtocol: tcp

  WorkerIngressWorkerKube:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Internal Kubernetes communication
      FromPort: 10250
      ToPort: 10250
      IpProtocol: tcp

  WorkerIngressIngressServices:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Kubernetes ingress services
      FromPort: 30000
      ToPort: 32767
      IpProtocol: tcp

  WorkerIngressMasterIngressServices:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Kubernetes ingress services
      FromPort: 30000
      ToPort: 32767
      IpProtocol: tcp

  WorkerIngressIngressServicesUDP:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt WorkerSecurityGroup.GroupId
      Description: Kubernetes ingress services
      FromPort: 30000
      ToPort: 32767
      IpProtocol: udp

  WorkerIngressMasterIngressServicesUDP:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt WorkerSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt MasterSecurityGroup.GroupId
      Description: Kubernetes ingress services
      FromPort: 30000
      ToPort: 32767
      IpProtocol: udp

  MasterIamRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
        - Effect: "Allow"
          Principal:
            Service:
            - "ec2.amazonaws.com"
          Action:
          - "sts:AssumeRole"
      Policies:
      - PolicyName: !Join ["-", [!Ref InfrastructureName, "master", "policy"]]
        PolicyDocument:
          Version: "2012-10-17"
          Statement:
          - Effect: "Allow"
            Action:
            - "ec2:AttachVolume"
            - "ec2:AuthorizeSecurityGroupIngress"
            - "ec2:CreateSecurityGroup"
            - "ec2:CreateTags"
            - "ec2:CreateVolume"
            - "ec2:DeleteSecurityGroup"
            - "ec2:DeleteVolume"
            - "ec2:Describe*"
            - "ec2:DetachVolume"
            - "ec2:ModifyInstanceAttribute"
            - "ec2:ModifyVolume"
            - "ec2:RevokeSecurityGroupIngress"
            - "elasticloadbalancing:AddTags"
            - "elasticloadbalancing:AttachLoadBalancerToSubnets"
            - "elasticloadbalancing:ApplySecurityGroupsToLoadBalancer"
            - "elasticloadbalancing:CreateListener"
            - "elasticloadbalancing:CreateLoadBalancer"
            - "elasticloadbalancing:CreateLoadBalancerPolicy"
            - "elasticloadbalancing:CreateLoadBalancerListeners"
            - "elasticloadbalancing:CreateTargetGroup"
            - "elasticloadbalancing:ConfigureHealthCheck"
            - "elasticloadbalancing:DeleteListener"
            - "elasticloadbalancing:DeleteLoadBalancer"
            - "elasticloadbalancing:DeleteLoadBalancerListeners"
            - "elasticloadbalancing:DeleteTargetGroup"
            - "elasticloadbalancing:DeregisterInstancesFromLoadBalancer"
            - "elasticloadbalancing:DeregisterTargets"
            - "elasticloadbalancing:Describe*"
            - "elasticloadbalancing:DetachLoadBalancerFromSubnets"
            - "elasticloadbalancing:ModifyListener"
            - "elasticloadbalancing:ModifyLoadBalancerAttributes"
            - "elasticloadbalancing:ModifyTargetGroup"
            - "elasticloadbalancing:ModifyTargetGroupAttributes"
            - "elasticloadbalancing:RegisterInstancesWithLoadBalancer"
            - "elasticloadbalancing:RegisterTargets"
            - "elasticloadbalancing:SetLoadBalancerPoliciesForBackendServer"
            - "elasticloadbalancing:SetLoadBalancerPoliciesOfListener"
            - "kms:DescribeKey"
            Resource: "*"

  MasterInstanceProfile:
    Type: "AWS::IAM::InstanceProfile"
    Properties:
      Roles:
      - Ref: "MasterIamRole"

  WorkerIamRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
        - Effect: "Allow"
          Principal:
            Service:
            - "ec2.amazonaws.com"
          Action:
          - "sts:AssumeRole"
      Policies:
      - PolicyName: !Join ["-", [!Ref InfrastructureName, "worker", "policy"]]
        PolicyDocument:
          Version: "2012-10-17"
          Statement:
          - Effect: "Allow"
            Action:
            - "ec2:DescribeInstances"
            - "ec2:DescribeRegions"
            Resource: "*"

  WorkerInstanceProfile:
    Type: "AWS::IAM::InstanceProfile"
    Properties:
      Roles:
      - Ref: "WorkerIamRole"

Outputs:
  MasterSecurityGroupId:
    Description: Master Security Group ID
    Value: !GetAtt MasterSecurityGroup.GroupId

  WorkerSecurityGroupId:
    Description: Worker Security Group ID
    Value: !GetAtt WorkerSecurityGroup.GroupId

  MasterInstanceProfile:
    Description: Master IAM Instance Profile
    Value: !Ref MasterInstanceProfile

  WorkerInstanceProfile:
    Description: Worker IAM Instance Profile
    Value: !Ref WorkerInstanceProfile

4.4.8. Accessing RHCOS AMIs with stream metadata

To find the correct RHCOS boot image for your cluster, you can use stream metadata, which provides standardized information about RHCOS in the JSON format.

You can use the coreos print-stream-json subcommand of openshift-install to access information about the boot images in the stream metadata format. This command provides a method for printing stream metadata in a scriptable, machine-readable format.

For user-provisioned installations, the openshift-install binary has references to the version of RHCOS boot images that are tested for use with OpenShift Container Platform, such as the Amazon Web Services (AWS) AMI.

To parse the stream metadata, use one of the following methods:

Procedure

  • From a Go program, use the official stream-metadata-go library at https://github.com/coreos/stream-metadata-go. You can also view example code in the library.
  • From another programming language, such as Python or Ruby, use the JSON library of your preferred programming language.
  • From a command-line utility that handles JSON data, such as jq, print the current x86_64 or aarch64 AMI for an AWS region, such as us-west-1:

    For x86_64

    $ openshift-install coreos print-stream-json | jq -r '.architectures.x86_64.images.aws.regions["us-west-1"].image'

    Example output

    ami-0d3e625f84626bbda

    For aarch64

    $ openshift-install coreos print-stream-json | jq -r '.architectures.aarch64.images.aws.regions["us-west-1"].image'

    Example output

    ami-0af1d3b7fa5be2131

    The output of this command is the AWS AMI ID for your designated architecture and the us-west-1 region. The AMI must belong to the same region as the cluster.

4.4.9. RHCOS AMIs for the AWS infrastructure

To deploy OpenShift Container Platform nodes on Amazon Web Services (AWS), select from the valid Red Hat Enterprise Linux CoreOS (RHCOS) AMIs for your region and instance architecture.

Note

By importing your own AMI, you can also install to regions that do not have a published RHCOS AMI.

Table 4.11. x86_64 RHCOS AMIs
AWS zoneAWS AMI

af-south-1

ami-0a3b22174319ad66e

ap-east-1

ami-09cde51703738523d

ap-east-2

ami-05478426f756db81c

ap-northeast-1

ami-0d6f0c1a044b6848f

ap-northeast-2

ami-0d19d79e52ad365c8

ap-northeast-3

ami-0a0391de700b812ae

ap-south-1

ami-097ffb6f644b7bad1

ap-south-2

ami-08f1c0c6caafcf2c5

ap-southeast-1

ami-09b223a7c699ecde8

ap-southeast-2

ami-0a44bb6d4903a93a1

ap-southeast-3

ami-01469b817e364700f

ap-southeast-4

ami-086cc002b6d450301

ap-southeast-5

ami-0b5b9be3ea6fc17de

ap-southeast-6

ami-03a6ddee59246ab62

ap-southeast-7

ami-03ce4d4bb4f67e777

ca-central-1

ami-0b23054e68ef5ec3b

ca-west-1

ami-0541a60892c677593

eu-central-1

ami-006a33223c87af648

eu-central-2

ami-05ddf59e283155ea1

eu-north-1

ami-054f384036093db98

eu-south-1

ami-0a1cc6a65238669f3

eu-south-2

ami-0fe02b801fea5edf6

eu-west-1

ami-0632ffa330e30aea1

eu-west-2

ami-05829d8d5c031e4a8

eu-west-3

ami-00be64f508df27900

il-central-1

ami-0eeea15b1c070e051

me-central-1

ami-090084b481adf23e9

me-south-1

ami-0569abe19529c8b10

mx-central-1

ami-05ab0cf33b0e946a7

sa-east-1

ami-04dd4c56b43a23fb5

us-east-1

ami-04018496b0a1da2d2

us-east-2

ami-0b264801b0e00009c

us-gov-east-1

ami-042feba6717887157

us-gov-west-1

ami-0b05862564ac8353d

us-west-1

ami-08f548f5be577ce2d

us-west-2

ami-04941543f3e575579

Table 4.12. aarch64 RHCOS AMIs
AWS zoneAWS AMI

af-south-1

ami-0265ec024c31e7603

ap-east-1

ami-01d0891e1fa7c28fe

ap-east-2

ami-0de88496066d7428e

ap-northeast-1

ami-0d7c8859dc8f2ac02

ap-northeast-2

ami-00377959ff7cf0ed6

ap-northeast-3

ami-095386042a7673286

ap-south-1

ami-09f0f012b2c626f59

ap-south-2

ami-01c8221c9a56e0c74

ap-southeast-1

ami-0c27520bfa297e78a

ap-southeast-2

ami-0af72833671d615f1

ap-southeast-3

ami-085607af8f322e956

ap-southeast-4

ami-03d8bfd58de713367

ap-southeast-5

ami-0f6479fb82d8108d1

ap-southeast-6

ami-0a6a284e74f2e9afd

ap-southeast-7

ami-054eb3c4286f4dbca

ca-central-1

ami-032e08fde31f0a6cc

ca-west-1

ami-07d83e72beff3eb6c

eu-central-1

ami-0a62c879da82e8f99

eu-central-2

ami-09c91e670678ce2c1

eu-north-1

ami-0e896b8e4e7de42be

eu-south-1

ami-01718000bd7650956

eu-south-2

ami-02c48b6c8488542b2

eu-west-1

ami-06ea845fe728a8891

eu-west-2

ami-0e6c67a8674179e1b

eu-west-3

ami-0c4cb83cc7e4ec057

il-central-1

ami-00a88a6e634ac6676

me-central-1

ami-09aff5ac8bd25e9b8

me-south-1

ami-043e9d5894e68426d

mx-central-1

ami-00c0f1b2fc7ab92d4

sa-east-1

ami-0af3988f6b0fbee7f

us-east-1

ami-02ffd1d5ed7351ceb

us-east-2

ami-0d08ccc7bcf77433d

us-gov-east-1

ami-0b183fafd7eeae965

us-gov-west-1

ami-0411a4dd8cbf726db

us-west-1

ami-06149aec55f3e1d6c

us-west-2

ami-0c2bafedf2fc1dfc3

4.4.10. Creating the bootstrap node in AWS

To initialize the OpenShift Container Platform control plane, create the bootstrap node in Amazon Web Services (AWS) by uploading the Ignition config to an S3 bucket and launching the CloudFormation template.

  • Providing a location to serve the bootstrap.ign Ignition config file to your cluster. This file is in your installation directory. The provided CloudFormation template assumes that you serve the Ignition config files for your cluster from an S3 bucket. If you choose to serve the files from another location, you must change the templates.
  • Using the provided CloudFormation template and a custom parameter file to create a stack of AWS resources. The stack represents the bootstrap node that your OpenShift Container Platform installation requires.
Note

If you do not use the provided CloudFormation template to create your bootstrap node, you must review the provided information and manually create the infrastructure. If your cluster does not initialize correctly, you might have to contact Red Hat support with your installation logs.

Prerequisites

  • You created and configured DNS, load balancers, and listeners in AWS.
  • You created the security groups and roles required for your cluster in AWS.

Procedure

  1. Create the bucket by running the following command:

    $ aws s3 mb s3://<cluster_name>-infra

    where <cluster_name>-infra is the bucket name. When creating the install-config.yaml file, replace <cluster_name> with the name specified for the cluster.

    You must use a presigned URL for your S3 bucket, instead of the s3:// schema, if you are:

    • Deploying to a region that has endpoints that differ from the AWS SDK.
    • Deploying a proxy.
    • Providing your own custom endpoints.
  2. Upload the bootstrap.ign Ignition config file to the bucket by running the following command:

    $ aws s3 cp <installation_directory>/bootstrap.ign s3://<cluster_name>-infra/bootstrap.ign

    where <installation_directory> is the path to the directory that you stored the installation files in.

  3. Verify that the file uploaded by running the following command:

    $ aws s3 ls s3://<cluster_name>-infra/

    Example output

    2019-04-03 16:15:16     314878 bootstrap.ign

    Note

    The bootstrap Ignition config file does have secrets, such as X.509 keys. The following steps give basic security for the S3 bucket. To give additional security, you can enable an S3 bucket policy to allow only certain users, such as the OpenShift IAM user, to access objects that the bucket has. You can avoid S3 entirely and serve your bootstrap Ignition config file from any address that the bootstrap machine can reach.

  4. Create a JSON file that has the parameter values that the template requires:

    [
      {
        "ParameterKey": "InfrastructureName",
        "ParameterValue": "mycluster-<random_string>"
      },
      {
        "ParameterKey": "RhcosAmi",
        "ParameterValue": "ami-<random_string>"
      },
      {
        "ParameterKey": "AllowedBootstrapSshCidr",
        "ParameterValue": "0.0.0.0/0"
      },
      {
        "ParameterKey": "PublicSubnet",
        "ParameterValue": "subnet-<random_string>"
      },
      {
        "ParameterKey": "MasterSecurityGroupId",
        "ParameterValue": "sg-<random_string>"
      },
      {
        "ParameterKey": "VpcId",
        "ParameterValue": "vpc-<random_string>"
      },
      {
        "ParameterKey": "BootstrapIgnitionLocation",
        "ParameterValue": "s3://<bucket_name>/bootstrap.ign"
      },
      {
        "ParameterKey": "AutoRegisterELB",
        "ParameterValue": "yes"
      },
      {
        "ParameterKey": "RegisterNlbIpTargetsLambdaArn",
        "ParameterValue": "arn:aws:lambda:<aws_region>:<account_number>:function:<dns_stack_name>-RegisterNlbIpTargets-<random_string>"
      },
      {
        "ParameterKey": "ExternalApiTargetGroupArn",
        "ParameterValue": "arn:aws:elasticloadbalancing:<aws_region>:<account_number>:targetgroup/<dns_stack_name>-Exter-<random_string>"
      },
      {
        "ParameterKey": "InternalApiTargetGroupArn",
        "ParameterValue": "arn:aws:elasticloadbalancing:<aws_region>:<account_number>:targetgroup/<dns_stack_name>-Inter-<random_string>"
      },
      {
        "ParameterKey": "InternalServiceTargetGroupArn",
        "ParameterValue": "arn:aws:elasticloadbalancing:<aws_region>:<account_number>:targetgroup/<dns_stack_name>-Inter-<random_string>"
      }
    ]

    where:

    InfrastructureName
    Specifies the name for your cluster infrastructure that your Ignition config files encode for the cluster. Specify the infrastructure name that you extracted from the Ignition config file metadata, which has the format <cluster_name>-<random_string>.
    RhcosAmi
    Specifies the current Red Hat Enterprise Linux CoreOS (RHCOS) AMI to use for the bootstrap node based on your selected architecture. Specify a valid AWS::EC2::Image::Id value.
    AllowedBootstrapSshCidr
    Specifies the CIDR block to allow SSH access to the bootstrap node. Specify a CIDR block in the format x.x.x.x/16-24.
    PublicSubnet
    Specifies the public subnet in your VPC to launch the bootstrap node into. Specify the PublicSubnetIds value from the output of the CloudFormation template for the VPC.
    MasterSecurityGroupId
    Specifies the control plane security group ID for registering temporary rules. Specify the MasterSecurityGroupId value from the output of the CloudFormation template for the security group and roles.
    VpcId
    Specifies the VPC that the created resources will belong to. Specify the VpcId value from the output of the CloudFormation template for the VPC.
    BootstrapIgnitionLocation
    Specifies the location to fetch the bootstrap Ignition config file from. Specify the S3 bucket and file name in the form s3://<bucket_name>/bootstrap.ign.
    AutoRegisterELB
    Specifies whether to register a network load balancer (NLB). Specify yes or no. If you specify yes, you must give a Lambda Amazon Resource Name (ARN) value.
    RegisterNlbIpTargetsLambdaArn
    Specifies the ARN for NLB IP target registration lambda group. Specify the RegisterNlbIpTargetsLambda value from the output of the CloudFormation template for DNS and load balancing. Use arn:aws-us-gov if deploying the cluster to an AWS GovCloud region.
    ExternalApiTargetGroupArn
    Specifies the ARN for external API load balancer target group. Specify the ExternalApiTargetGroupArn value from the output of the CloudFormation template for DNS and load balancing. Use arn:aws-us-gov if deploying the cluster to an AWS GovCloud region.
    InternalApiTargetGroupArn
    Specifies the ARN for internal API load balancer target group. Specify the InternalApiTargetGroupArn value from the output of the CloudFormation template for DNS and load balancing. Use arn:aws-us-gov if deploying the cluster to an AWS GovCloud region.
    InternalServiceTargetGroupArn
    Specifies the ARN for internal service load balancer target group. Specify the InternalServiceTargetGroupArn value from the output of the CloudFormation template for DNS and load balancing. Use arn:aws-us-gov if deploying the cluster to an AWS GovCloud region.
  5. Copy the template from the CloudFormation template for the bootstrap machine section and save it as a YAML file on your computer. This template describes the bootstrap machine that your cluster requires.
  6. Optional: If you are deploying the cluster with a proxy, you must update the ignition in the template to add the ignition.config.proxy fields. Additionally, If you have added the Amazon EC2, Elastic Load Balancing, and S3 VPC endpoints to your VPC, you must add these endpoints to the noProxy field.
  7. Launch the CloudFormation template to create a stack of AWS resources that represent the bootstrap node:

    Important

    You must enter the command on a single line.

    $ aws cloudformation create-stack --stack-name <name> \
         --template-body file://<template>.yaml \
         --parameters file://<parameters>.json \
         --capabilities CAPABILITY_NAMED_IAM

    where:

    <name>
    Specifies the name for the CloudFormation stack, such as cluster-bootstrap. You need the name of this stack if you remove the cluster.
    <template>
    Specifies the relative path to and name of the CloudFormation template YAML file that you saved.
    <parameters>
    Specifies the relative path to and name of the CloudFormation parameters JSON file.
    CAPABILITY_NAMED_IAM
    You must explicitly declare this capability because the provided template creates some AWS::IAM::Role and AWS::IAM::InstanceProfile resources.

    Example output

    arn:aws:cloudformation:us-east-1:269333783861:stack/cluster-bootstrap/12944486-2add-11eb-9dee-12dace8e3a83

  8. Confirm that the template components exist:

    $ aws cloudformation describe-stacks --stack-name <name>

    After the StackStatus displays CREATE_COMPLETE, the output displays values for the following parameters. You must give these parameter values to the other CloudFormation templates that you run to create your cluster:

    BootstrapInstanceId

    The bootstrap Instance ID.

    BootstrapPublicIp

    The bootstrap node public IP address.

    BootstrapPrivateIp

    The bootstrap node private IP address.

4.4.10.1. CloudFormation template for the bootstrap machine

The bootstrap machine CloudFormation template creates the temporary Amazon Web Services (AWS) resources that the OpenShift Container Platform bootstrap process requires to initialize the control plane.

CloudFormation template for the bootstrap machine

AWSTemplateFormatVersion: 2010-09-09
Description: Template for OpenShift Cluster Bootstrap (EC2 Instance, Security Groups and IAM)

Parameters:
  InfrastructureName:
    AllowedPattern: ^([a-zA-Z][a-zA-Z0-9\-]{0,26})$
    MaxLength: 27
    MinLength: 1
    ConstraintDescription: Infrastructure name must be alphanumeric, start with a letter, and have a maximum of 27 characters.
    Description: A short, unique cluster ID used to tag cloud resources and identify items owned or used by the cluster.
    Type: String
  RhcosAmi:
    Description: Current Red Hat Enterprise Linux CoreOS AMI to use for bootstrap.
    Type: AWS::EC2::Image::Id
  AllowedBootstrapSshCidr:
    AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|1[0-9]|2[0-9]|3[0-2]))$
    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/0-32.
    Default: 0.0.0.0/0
    Description: CIDR block to allow SSH access to the bootstrap node.
    Type: String
  PublicSubnet:
    Description: The public subnet to launch the bootstrap node into.
    Type: AWS::EC2::Subnet::Id
  MasterSecurityGroupId:
    Description: The master security group ID for registering temporary rules.
    Type: AWS::EC2::SecurityGroup::Id
  VpcId:
    Description: The VPC-scoped resources will belong to this VPC.
    Type: AWS::EC2::VPC::Id
  BootstrapIgnitionLocation:
    Default: s3://my-s3-bucket/bootstrap.ign
    Description: Ignition config file location.
    Type: String
  AutoRegisterELB:
    Default: "yes"
    AllowedValues:
    - "yes"
    - "no"
    Description: Do you want to invoke NLB registration, which requires a Lambda ARN parameter?
    Type: String
  RegisterNlbIpTargetsLambdaArn:
    Description: ARN for NLB IP target registration lambda.
    Type: String
  ExternalApiTargetGroupArn:
    Description: ARN for external API load balancer target group.
    Type: String
  InternalApiTargetGroupArn:
    Description: ARN for internal API load balancer target group.
    Type: String
  InternalServiceTargetGroupArn:
    Description: ARN for internal service load balancer target group.
    Type: String
  BootstrapInstanceType:
    Description: Instance type for the bootstrap EC2 instance
    Default: "i3.large"
    Type: String

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
    - Label:
        default: "Cluster Information"
      Parameters:
      - InfrastructureName
    - Label:
        default: "Host Information"
      Parameters:
      - RhcosAmi
      - BootstrapIgnitionLocation
      - MasterSecurityGroupId
    - Label:
        default: "Network Configuration"
      Parameters:
      - VpcId
      - AllowedBootstrapSshCidr
      - PublicSubnet
    - Label:
        default: "Load Balancer Automation"
      Parameters:
      - AutoRegisterELB
      - RegisterNlbIpTargetsLambdaArn
      - ExternalApiTargetGroupArn
      - InternalApiTargetGroupArn
      - InternalServiceTargetGroupArn
    ParameterLabels:
      InfrastructureName:
        default: "Infrastructure Name"
      VpcId:
        default: "VPC ID"
      AllowedBootstrapSshCidr:
        default: "Allowed SSH Source"
      PublicSubnet:
        default: "Public Subnet"
      RhcosAmi:
        default: "Red Hat Enterprise Linux CoreOS AMI ID"
      BootstrapIgnitionLocation:
        default: "Bootstrap Ignition Source"
      MasterSecurityGroupId:
        default: "Master Security Group ID"
      AutoRegisterELB:
        default: "Use Provided ELB Automation"

Conditions:
  DoRegistration: !Equals ["yes", !Ref AutoRegisterELB]

Resources:
  BootstrapIamRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
        - Effect: "Allow"
          Principal:
            Service:
            - "ec2.amazonaws.com"
          Action:
          - "sts:AssumeRole"
      Path: "/"
      Policies:
      - PolicyName: !Join ["-", [!Ref InfrastructureName, "bootstrap", "policy"]]
        PolicyDocument:
          Version: "2012-10-17"
          Statement:
          - Effect: "Allow"
            Action: "ec2:Describe*"
            Resource: "*"
          - Effect: "Allow"
            Action: "ec2:AttachVolume"
            Resource: "*"
          - Effect: "Allow"
            Action: "ec2:DetachVolume"
            Resource: "*"
          - Effect: "Allow"
            Action: "s3:GetObject"
            Resource: "*"

  BootstrapInstanceProfile:
    Type: "AWS::IAM::InstanceProfile"
    Properties:
      Path: "/"
      Roles:
      - Ref: "BootstrapIamRole"

  BootstrapSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Cluster Bootstrap Security Group
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: 22
        ToPort: 22
        CidrIp: !Ref AllowedBootstrapSshCidr
      - IpProtocol: tcp
        ToPort: 19531
        FromPort: 19531
        CidrIp: 0.0.0.0/0
      VpcId: !Ref VpcId

  BootstrapInstance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref RhcosAmi
      IamInstanceProfile: !Ref BootstrapInstanceProfile
      InstanceType: !Ref BootstrapInstanceType
      NetworkInterfaces:
      - AssociatePublicIpAddress: "true"
        DeviceIndex: "0"
        GroupSet:
        - !Ref "BootstrapSecurityGroup"
        - !Ref "MasterSecurityGroupId"
        SubnetId: !Ref "PublicSubnet"
      UserData:
        Fn::Base64: !Sub
        - '{"ignition":{"config":{"replace":{"source":"${S3Loc}"}},"version":"3.1.0"}}'
        - {
          S3Loc: !Ref BootstrapIgnitionLocation
        }

  RegisterBootstrapApiTarget:
    Condition: DoRegistration
    Type: Custom::NLBRegister
    Properties:
      ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
      TargetArn: !Ref ExternalApiTargetGroupArn
      TargetIp: !GetAtt BootstrapInstance.PrivateIp

  RegisterBootstrapInternalApiTarget:
    Condition: DoRegistration
    Type: Custom::NLBRegister
    Properties:
      ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
      TargetArn: !Ref InternalApiTargetGroupArn
      TargetIp: !GetAtt BootstrapInstance.PrivateIp

  RegisterBootstrapInternalServiceTarget:
    Condition: DoRegistration
    Type: Custom::NLBRegister
    Properties:
      ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
      TargetArn: !Ref InternalServiceTargetGroupArn
      TargetIp: !GetAtt BootstrapInstance.PrivateIp

Outputs:
  BootstrapInstanceId:
    Description: Bootstrap Instance ID.
    Value: !Ref BootstrapInstance

  BootstrapPublicIp:
    Description: The bootstrap node public IP address.
    Value: !GetAtt BootstrapInstance.PublicIp

  BootstrapPrivateIp:
    Description: The bootstrap node private IP address.
    Value: !GetAtt BootstrapInstance.PrivateIp

4.4.10.2. Creating the control plane machines in AWS

To run the OpenShift Container Platform control plane, create the three control plane machines in Amazon Web Services (AWS) by using the provided CloudFormation template and a custom parameter file.

Important

The CloudFormation template creates a stack that represents three control plane nodes.

Note

If you do not use the provided CloudFormation template to create your control plane nodes, you must review the provided information and manually create the infrastructure. If your cluster does not initialize correctly, you might have to contact Red Hat support with your installation logs.

Prerequisites

  • You created the bootstrap machine.

Procedure

  1. Create a JSON file that has the parameter values that the template requires:

    [
      {
        "ParameterKey": "InfrastructureName",
        "ParameterValue": "mycluster-<random_string>"
      },
      {
        "ParameterKey": "RhcosAmi",
        "ParameterValue": "ami-<random_string>"
      },
      {
        "ParameterKey": "AutoRegisterDNS",
        "ParameterValue": "yes"
      },
      {
        "ParameterKey": "PrivateHostedZoneId",
        "ParameterValue": "<random_string>"
      },
      {
        "ParameterKey": "PrivateHostedZoneName",
        "ParameterValue": "mycluster.example.com"
      },
      {
        "ParameterKey": "Master0Subnet",
        "ParameterValue": "subnet-<random_string>"
      },
      {
        "ParameterKey": "Master1Subnet",
        "ParameterValue": "subnet-<random_string>"
      },
      {
        "ParameterKey": "Master2Subnet",
        "ParameterValue": "subnet-<random_string>"
      },
      {
        "ParameterKey": "MasterSecurityGroupId",
        "ParameterValue": "sg-<random_string>"
      },
      {
        "ParameterKey": "IgnitionLocation",
        "ParameterValue": "https://api-int.<cluster_name>.<domain_name>:22623/config/master"
      },
      {
        "ParameterKey": "CertificateAuthorities",
        "ParameterValue": "data:text/plain;charset=utf-8;base64,ABC...xYz=="
      },
      {
        "ParameterKey": "MasterInstanceProfileName",
        "ParameterValue": "<roles_stack>-MasterInstanceProfile-<random_string>"
      },
      {
        "ParameterKey": "MasterInstanceType",
        "ParameterValue": ""
      },
      {
        "ParameterKey": "AutoRegisterELB",
        "ParameterValue": "yes"
      },
      {
        "ParameterKey": "RegisterNlbIpTargetsLambdaArn",
        "ParameterValue": "arn:aws:lambda:<aws_region>:<account_number>:function:<dns_stack_name>-RegisterNlbIpTargets-<random_string>"
      },
      {
        "ParameterKey": "ExternalApiTargetGroupArn",
        "ParameterValue": "arn:aws:elasticloadbalancing:<aws_region>:<account_number>:targetgroup/<dns_stack_name>-Exter-<random_string>"
      },
      {
        "ParameterKey": "InternalApiTargetGroupArn",
        "ParameterValue": "arn:aws:elasticloadbalancing:<aws_region>:<account_number>:targetgroup/<dns_stack_name>-Inter-<random_string>"
      },
      {
        "ParameterKey": "InternalServiceTargetGroupArn",
        "ParameterValue": "arn:aws:elasticloadbalancing:<aws_region>:<account_number>:targetgroup/<dns_stack_name>-Inter-<random_string>"
      }
    ]

    where:

    InfrastructureName
    Specifies the name for your cluster infrastructure that your Ignition config files encode for the cluster. Specify the infrastructure name that you extracted from the Ignition config file metadata, which has the format <cluster_name>-<random_string>.
    RhcosAmi
    Specifies the current Red Hat Enterprise Linux CoreOS (RHCOS) AMI to use for the control plane machines based on your selected architecture. Specify an AWS::EC2::Image::Id value.
    AutoRegisterDNS
    Specifies whether to perform DNS etcd registration. Specify yes or no. If you specify yes, you must give hosted zone information.
    PrivateHostedZoneId
    Specifies the Route 53 private zone ID to register the etcd targets with. Specify the PrivateHostedZoneId value from the output of the CloudFormation template for DNS and load balancing.
    PrivateHostedZoneName
    Specifies the Route 53 zone to register the targets with. Specify <cluster_name>.<domain_name> where <domain_name> is the Route 53 base domain that you used when you generated the install-config.yaml file for the cluster. Do not include the trailing period (.) that is displayed in the AWS console.
    Master0Subnet, Master1Subnet, Master2Subnet
    Specifies a subnet, preferably private, to launch the control plane machines on. Specify a subnet from the PrivateSubnets value from the output of the CloudFormation template for DNS and load balancing.
    MasterSecurityGroupId
    Specifies the control plane security group ID to associate with control plane nodes. Specify the MasterSecurityGroupId value from the output of the CloudFormation template for the security group and roles.
    IgnitionLocation
    Specifies the location to fetch the control plane Ignition config file from. Specify the generated Ignition config file location, https://api-int.<cluster_name>.<domain_name>:22623/config/master.
    CertificateAuthorities
    Specifies the base64 encoded certificate authority string to use. Specify the value from the master.ign file that is in the installation directory. This value is the long string with the format data:text/plain;charset=utf-8;base64,ABC…​xYz==.
    MasterInstanceProfileName
    Specifies the IAM profile to associate with control plane nodes. Specify the MasterInstanceProfile parameter value from the output of the CloudFormation template for the security group and roles.
    MasterInstanceType
    Specifies the type of AWS instance to use for the control plane machines based on your selected architecture. The instance type value corresponds to the minimum resource requirements for control plane machines. For example m6i.xlarge is a type for AMD64 and m6g.xlarge is a type for ARM64.
    AutoRegisterELB
    Specifies whether to register a network load balancer (NLB). Specify yes or no. If you specify yes, you must give a Lambda Amazon Resource Name (ARN) value.
    RegisterNlbIpTargetsLambdaArn
    Specifies the ARN for NLB IP target registration lambda group. Specify the RegisterNlbIpTargetsLambda value from the output of the CloudFormation template for DNS and load balancing. Use arn:aws-us-gov if deploying the cluster to an AWS GovCloud region.
    ExternalApiTargetGroupArn
    Specifies the ARN for external API load balancer target group. Specify the ExternalApiTargetGroupArn value from the output of the CloudFormation template for DNS and load balancing. Use arn:aws-us-gov if deploying the cluster to an AWS GovCloud region.
    InternalApiTargetGroupArn
    Specifies the ARN for internal API load balancer target group. Specify the InternalApiTargetGroupArn value from the output of the CloudFormation template for DNS and load balancing. Use arn:aws-us-gov if deploying the cluster to an AWS GovCloud region.
    InternalServiceTargetGroupArn
    Specifies the ARN for internal service load balancer target group. Specify the InternalServiceTargetGroupArn value from the output of the CloudFormation template for DNS and load balancing. Use arn:aws-us-gov if deploying the cluster to an AWS GovCloud region.
  2. Copy the template from the CloudFormation template for control plane machines section and save it as a YAML file on your computer. This template describes the control plane machines that your cluster requires.
  3. If you specified an m5 instance type as the value for MasterInstanceType, add that instance type to the MasterInstanceType.AllowedValues parameter in the CloudFormation template.
  4. Launch the CloudFormation template to create a stack of AWS resources that represent the control plane nodes:

    Important

    You must enter the command on a single line.

    $ aws cloudformation create-stack --stack-name <name> \
         --template-body file://<template>.yaml \
         --parameters file://<parameters>.json

    where:

    <name>
    Specifies the name for the CloudFormation stack, such as cluster-control-plane. You need the name of this stack if you remove the cluster.
    <template>
    Specifies the relative path to and name of the CloudFormation template YAML file that you saved.
    <parameters>
    Specifies the relative path to and name of the CloudFormation parameters JSON file.

    Example output

    arn:aws:cloudformation:us-east-1:269333783861:stack/cluster-control-plane/21c7e2b0-2ee2-11eb-c6f6-0aa34627df4b

    Note

    The CloudFormation template creates a stack that represents three control plane nodes.

  5. Confirm that the template components exist:

    $ aws cloudformation describe-stacks --stack-name <name>

4.4.10.3. CloudFormation template for control plane machines

The control plane CloudFormation template creates the Amazon Web Services (AWS) resources for the three control plane machines that manage your OpenShift Container Platform cluster.

CloudFormation template for control plane machines

AWSTemplateFormatVersion: 2010-09-09
Description: Template for OpenShift Cluster Node Launch (EC2 master instances)

Parameters:
  InfrastructureName:
    AllowedPattern: ^([a-zA-Z][a-zA-Z0-9\-]{0,26})$
    MaxLength: 27
    MinLength: 1
    ConstraintDescription: Infrastructure name must be alphanumeric, start with a letter, and have a maximum of 27 characters.
    Description: A short, unique cluster ID used to tag nodes for the kubelet cloud provider.
    Type: String
  RhcosAmi:
    Description: Current Red Hat Enterprise Linux CoreOS AMI to use for bootstrap.
    Type: AWS::EC2::Image::Id
  AutoRegisterDNS:
    Default: ""
    Description: unused
    Type: String
  PrivateHostedZoneId:
    Default: ""
    Description: unused
    Type: String
  PrivateHostedZoneName:
    Default: ""
    Description: unused
    Type: String
  Master0Subnet:
    Description: The subnets, recommend private, to launch the master nodes into.
    Type: AWS::EC2::Subnet::Id
  Master1Subnet:
    Description: The subnets, recommend private, to launch the master nodes into.
    Type: AWS::EC2::Subnet::Id
  Master2Subnet:
    Description: The subnets, recommend private, to launch the master nodes into.
    Type: AWS::EC2::Subnet::Id
  MasterSecurityGroupId:
    Description: The master security group ID to associate with master nodes.
    Type: AWS::EC2::SecurityGroup::Id
  IgnitionLocation:
    Default: https://api-int.$CLUSTER_NAME.$DOMAIN:22623/config/master
    Description: Ignition config file location.
    Type: String
  CertificateAuthorities:
    Default: data:text/plain;charset=utf-8;base64,ABC...xYz==
    Description: Base64 encoded certificate authority string to use.
    Type: String
  MasterInstanceProfileName:
    Description: IAM profile to associate with master nodes.
    Type: String
  MasterInstanceType:
    Default: m5.xlarge
    Type: String

  AutoRegisterELB:
    Default: "yes"
    AllowedValues:
    - "yes"
    - "no"
    Description: Do you want to invoke NLB registration, which requires a Lambda ARN parameter?
    Type: String
  RegisterNlbIpTargetsLambdaArn:
    Description: ARN for NLB IP target registration lambda. Supply the value from the cluster infrastructure or select "no" for AutoRegisterELB.
    Type: String
  ExternalApiTargetGroupArn:
    Description: ARN for external API load balancer target group. Supply the value from the cluster infrastructure or select "no" for AutoRegisterELB.
    Type: String
  InternalApiTargetGroupArn:
    Description: ARN for internal API load balancer target group. Supply the value from the cluster infrastructure or select "no" for AutoRegisterELB.
    Type: String
  InternalServiceTargetGroupArn:
    Description: ARN for internal service load balancer target group. Supply the value from the cluster infrastructure or select "no" for AutoRegisterELB.
    Type: String

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
    - Label:
        default: "Cluster Information"
      Parameters:
      - InfrastructureName
    - Label:
        default: "Host Information"
      Parameters:
      - MasterInstanceType
      - RhcosAmi
      - IgnitionLocation
      - CertificateAuthorities
      - MasterSecurityGroupId
      - MasterInstanceProfileName
    - Label:
        default: "Network Configuration"
      Parameters:
      - VpcId
      - AllowedBootstrapSshCidr
      - Master0Subnet
      - Master1Subnet
      - Master2Subnet
    - Label:
        default: "Load Balancer Automation"
      Parameters:
      - AutoRegisterELB
      - RegisterNlbIpTargetsLambdaArn
      - ExternalApiTargetGroupArn
      - InternalApiTargetGroupArn
      - InternalServiceTargetGroupArn
    ParameterLabels:
      InfrastructureName:
        default: "Infrastructure Name"
      VpcId:
        default: "VPC ID"
      Master0Subnet:
        default: "Master-0 Subnet"
      Master1Subnet:
        default: "Master-1 Subnet"
      Master2Subnet:
        default: "Master-2 Subnet"
      MasterInstanceType:
        default: "Master Instance Type"
      MasterInstanceProfileName:
        default: "Master Instance Profile Name"
      RhcosAmi:
        default: "Red Hat Enterprise Linux CoreOS AMI ID"
      BootstrapIgnitionLocation:
        default: "Master Ignition Source"
      CertificateAuthorities:
        default: "Ignition CA String"
      MasterSecurityGroupId:
        default: "Master Security Group ID"
      AutoRegisterELB:
        default: "Use Provided ELB Automation"

Conditions:
  DoRegistration: !Equals ["yes", !Ref AutoRegisterELB]

Resources:
  Master0:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref RhcosAmi
      BlockDeviceMappings:
      - DeviceName: /dev/xvda
        Ebs:
          VolumeSize: "120"
          VolumeType: "gp2"
      IamInstanceProfile: !Ref MasterInstanceProfileName
      InstanceType: !Ref MasterInstanceType
      NetworkInterfaces:
      - AssociatePublicIpAddress: "false"
        DeviceIndex: "0"
        GroupSet:
        - !Ref "MasterSecurityGroupId"
        SubnetId: !Ref "Master0Subnet"
      UserData:
        Fn::Base64: !Sub
        - '{"ignition":{"config":{"merge":[{"source":"${SOURCE}"}]},"security":{"tls":{"certificateAuthorities":[{"source":"${CA_BUNDLE}"}]}},"version":"3.1.0"}}'
        - {
          SOURCE: !Ref IgnitionLocation,
          CA_BUNDLE: !Ref CertificateAuthorities,
        }
      Tags:
      - Key: !Join ["", ["kubernetes.io/cluster/", !Ref InfrastructureName]]
        Value: "shared"

  RegisterMaster0:
    Condition: DoRegistration
    Type: Custom::NLBRegister
    Properties:
      ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
      TargetArn: !Ref ExternalApiTargetGroupArn
      TargetIp: !GetAtt Master0.PrivateIp

  RegisterMaster0InternalApiTarget:
    Condition: DoRegistration
    Type: Custom::NLBRegister
    Properties:
      ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
      TargetArn: !Ref InternalApiTargetGroupArn
      TargetIp: !GetAtt Master0.PrivateIp

  RegisterMaster0InternalServiceTarget:
    Condition: DoRegistration
    Type: Custom::NLBRegister
    Properties:
      ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
      TargetArn: !Ref InternalServiceTargetGroupArn
      TargetIp: !GetAtt Master0.PrivateIp

  Master1:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref RhcosAmi
      BlockDeviceMappings:
      - DeviceName: /dev/xvda
        Ebs:
          VolumeSize: "120"
          VolumeType: "gp2"
      IamInstanceProfile: !Ref MasterInstanceProfileName
      InstanceType: !Ref MasterInstanceType
      NetworkInterfaces:
      - AssociatePublicIpAddress: "false"
        DeviceIndex: "0"
        GroupSet:
        - !Ref "MasterSecurityGroupId"
        SubnetId: !Ref "Master1Subnet"
      UserData:
        Fn::Base64: !Sub
        - '{"ignition":{"config":{"merge":[{"source":"${SOURCE}"}]},"security":{"tls":{"certificateAuthorities":[{"source":"${CA_BUNDLE}"}]}},"version":"3.1.0"}}'
        - {
          SOURCE: !Ref IgnitionLocation,
          CA_BUNDLE: !Ref CertificateAuthorities,
        }
      Tags:
      - Key: !Join ["", ["kubernetes.io/cluster/", !Ref InfrastructureName]]
        Value: "shared"

  RegisterMaster1:
    Condition: DoRegistration
    Type: Custom::NLBRegister
    Properties:
      ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
      TargetArn: !Ref ExternalApiTargetGroupArn
      TargetIp: !GetAtt Master1.PrivateIp

  RegisterMaster1InternalApiTarget:
    Condition: DoRegistration
    Type: Custom::NLBRegister
    Properties:
      ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
      TargetArn: !Ref InternalApiTargetGroupArn
      TargetIp: !GetAtt Master1.PrivateIp

  RegisterMaster1InternalServiceTarget:
    Condition: DoRegistration
    Type: Custom::NLBRegister
    Properties:
      ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
      TargetArn: !Ref InternalServiceTargetGroupArn
      TargetIp: !GetAtt Master1.PrivateIp

  Master2:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref RhcosAmi
      BlockDeviceMappings:
      - DeviceName: /dev/xvda
        Ebs:
          VolumeSize: "120"
          VolumeType: "gp2"
      IamInstanceProfile: !Ref MasterInstanceProfileName
      InstanceType: !Ref MasterInstanceType
      NetworkInterfaces:
      - AssociatePublicIpAddress: "false"
        DeviceIndex: "0"
        GroupSet:
        - !Ref "MasterSecurityGroupId"
        SubnetId: !Ref "Master2Subnet"
      UserData:
        Fn::Base64: !Sub
        - '{"ignition":{"config":{"merge":[{"source":"${SOURCE}"}]},"security":{"tls":{"certificateAuthorities":[{"source":"${CA_BUNDLE}"}]}},"version":"3.1.0"}}'
        - {
          SOURCE: !Ref IgnitionLocation,
          CA_BUNDLE: !Ref CertificateAuthorities,
        }
      Tags:
      - Key: !Join ["", ["kubernetes.io/cluster/", !Ref InfrastructureName]]
        Value: "shared"

  RegisterMaster2:
    Condition: DoRegistration
    Type: Custom::NLBRegister
    Properties:
      ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
      TargetArn: !Ref ExternalApiTargetGroupArn
      TargetIp: !GetAtt Master2.PrivateIp

  RegisterMaster2InternalApiTarget:
    Condition: DoRegistration
    Type: Custom::NLBRegister
    Properties:
      ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
      TargetArn: !Ref InternalApiTargetGroupArn
      TargetIp: !GetAtt Master2.PrivateIp

  RegisterMaster2InternalServiceTarget:
    Condition: DoRegistration
    Type: Custom::NLBRegister
    Properties:
      ServiceToken: !Ref RegisterNlbIpTargetsLambdaArn
      TargetArn: !Ref InternalServiceTargetGroupArn
      TargetIp: !GetAtt Master2.PrivateIp

Outputs:
  PrivateIPs:
    Description: The control-plane node private IP addresses.
    Value:
      !Join [
        ",",
        [!GetAtt Master0.PrivateIp, !GetAtt Master1.PrivateIp, !GetAtt Master2.PrivateIp]
      ]

4.4.11. Creating the worker nodes in AWS

To run application workloads on your OpenShift Container Platform cluster, create worker nodes in Amazon Web Services (AWS) by using the provided CloudFormation template.

You can use the provided CloudFormation template and a custom parameter file to create a stack of AWS resources that represent a worker node.

Important

The CloudFormation template creates a stack that represents one worker node. You must create a stack for each worker node.

Note

If you do not use the provided CloudFormation template to create your worker nodes, you must review the provided information and manually create the infrastructure. If your cluster does not initialize correctly, you might have to contact Red Hat support with your installation logs.

Prerequisites

  • You created the control plane machines.

Procedure

  1. Create a JSON file that contains the parameter values that the CloudFormation template requires:

    [
      {
        "ParameterKey": "InfrastructureName",
        "ParameterValue": "mycluster-<random_string>"
      },
      {
        "ParameterKey": "RhcosAmi",
        "ParameterValue": "ami-<random_string>"
      },
      {
        "ParameterKey": "Subnet",
        "ParameterValue": "subnet-<random_string>"
      },
      {
        "ParameterKey": "WorkerSecurityGroupId",
        "ParameterValue": "sg-<random_string>"
      },
      {
        "ParameterKey": "IgnitionLocation",
        "ParameterValue": "https://api-int.<cluster_name>.<domain_name>:22623/config/worker"
      },
      {
        "ParameterKey": "CertificateAuthorities",
        "ParameterValue": "data:text/plain;charset=utf-8;base64,ABC...xYz=="
      },
      {
        "ParameterKey": "WorkerInstanceProfileName",
        "ParameterValue": "<roles_stack>-WorkerInstanceProfile-<random_string>"
      },
      {
        "ParameterKey": "WorkerInstanceType",
        "ParameterValue": ""
      }
    ]

    where:

    InfrastructureName
    Specifies the name for your cluster infrastructure that is encoded in your Ignition config files for the cluster. Set the value to the infrastructure name that you extracted from the Ignition config file metadata, which has the format <cluster-name>-<random-string>.
    RhcosAmi
    Specifies the current Red Hat Enterprise Linux CoreOS (RHCOS) AMI to use for the worker nodes based on your selected architecture. Set the value to a valid AWS::EC2::Image::Id value.
    Subnet
    Specifies a subnet, preferably private, to start the worker nodes on. Set the value to a subnet from the PrivateSubnets value from the output of the CloudFormation template for DNS and load balancing.
    WorkerSecurityGroupId
    Specifies the worker security group ID to associate with worker nodes. Set the value to the WorkerSecurityGroupId value from the output of the CloudFormation template for the security group and roles.
    IgnitionLocation
    Specifies the location to fetch the bootstrap Ignition config file from. Set the value to the generated Ignition config location, https://api-int.<cluster_name>.<domain_name>:22623/config/worker.
    CertificateAuthorities
    Specifies the base64 encoded certificate authority string to use. Set the value to the value from the worker.ign file that is in the installation directory. This value is the long string with the format data:text/plain;charset=utf-8;base64,ABC…​xYz==.
    WorkerInstanceProfileName
    Specifies the IAM profile to associate with worker nodes. Set the value to the WorkerInstanceProfile parameter value from the output of the CloudFormation template for the security group and roles.
    WorkerInstanceType
    Specifies the type of AWS instance to use for the compute machines based on your selected architecture. The instance type value corresponds to the minimum resource requirements for compute machines. For example m6i.large is a type for AMD64 and m6g.large is a type for ARM64.
  2. Copy the template from the CloudFormation template for compute machines section of this topic and save it as a YAML file on your computer. This template describes the compute machines that your cluster requires.
  3. Optional: If you specified an m5 instance type as the value for WorkerInstanceType, add that instance type to the WorkerInstanceType.AllowedValues parameter in the CloudFormation template.
  4. Optional: If you are deploying with an AWS Marketplace image, update the Worker0.type.properties.ImageID parameter with the AMI ID that you obtained from your subscription.
  5. Use the CloudFormation template to create a stack of AWS resources that represent a worker node:

    Important

    You must enter the command on a single line.

    $ aws cloudformation create-stack --stack-name <name> \
         --template-body file://<template>.yaml \
         --parameters file://<parameters>.json

    where:

    <name>
    Specifies the name for the CloudFormation stack, such as cluster-worker-1. You need the name of this stack if you remove the cluster.
    <template>
    Specifies the relative path to and name of the CloudFormation template YAML file that you saved.
    <parameters>
    Specifies the relative path to and name of the CloudFormation parameters JSON file.

    Example output

    arn:aws:cloudformation:us-east-1:269333783861:stack/cluster-worker-1/729ee301-1c2a-11eb-348f-sd9888c65b59

    Note

    The CloudFormation template creates a stack that represents one worker node.

  6. Confirm that the template components exist:

    $ aws cloudformation describe-stacks --stack-name <name>
  7. Continue to create worker stacks until you have created enough worker machines for your cluster. You can create additional worker stacks by referencing the same template and parameter files and specifying a different stack name.

    Important

    You must create at least two worker machines, so you must create at least two stacks that use this CloudFormation template.

4.4.11.1. CloudFormation template for compute machines

The compute machine CloudFormation template creates the Amazon Web Services (AWS) resources for the worker nodes that run your OpenShift Container Platform application workloads.

CloudFormation template for compute machines

AWSTemplateFormatVersion: 2010-09-09
Description: Template for OpenShift Cluster Node Launch (EC2 worker instance)

Parameters:
  InfrastructureName:
    AllowedPattern: ^([a-zA-Z][a-zA-Z0-9\-]{0,26})$
    MaxLength: 27
    MinLength: 1
    ConstraintDescription: Infrastructure name must be alphanumeric, start with a letter, and have a maximum of 27 characters.
    Description: A short, unique cluster ID used to tag nodes for the kubelet cloud provider.
    Type: String
  RhcosAmi:
    Description: Current Red Hat Enterprise Linux CoreOS AMI to use for bootstrap.
    Type: AWS::EC2::Image::Id
  Subnet:
    Description: The subnets, recommend private, to launch the worker nodes into.
    Type: AWS::EC2::Subnet::Id
  WorkerSecurityGroupId:
    Description: The worker security group ID to associate with worker nodes.
    Type: AWS::EC2::SecurityGroup::Id
  IgnitionLocation:
    Default: https://api-int.$CLUSTER_NAME.$DOMAIN:22623/config/worker
    Description: Ignition config file location.
    Type: String
  CertificateAuthorities:
    Default: data:text/plain;charset=utf-8;base64,ABC...xYz==
    Description: Base64 encoded certificate authority string to use.
    Type: String
  WorkerInstanceProfileName:
    Description: IAM profile to associate with worker nodes.
    Type: String
  WorkerInstanceType:
    Default: m5.large
    Type: String

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
    - Label:
        default: "Cluster Information"
      Parameters:
      - InfrastructureName
    - Label:
        default: "Host Information"
      Parameters:
      - WorkerInstanceType
      - RhcosAmi
      - IgnitionLocation
      - CertificateAuthorities
      - WorkerSecurityGroupId
      - WorkerInstanceProfileName
    - Label:
        default: "Network Configuration"
      Parameters:
      - Subnet
    ParameterLabels:
      Subnet:
        default: "Subnet"
      InfrastructureName:
        default: "Infrastructure Name"
      WorkerInstanceType:
        default: "Worker Instance Type"
      WorkerInstanceProfileName:
        default: "Worker Instance Profile Name"
      RhcosAmi:
        default: "Red Hat Enterprise Linux CoreOS AMI ID"
      IgnitionLocation:
        default: "Worker Ignition Source"
      CertificateAuthorities:
        default: "Ignition CA String"
      WorkerSecurityGroupId:
        default: "Worker Security Group ID"

Resources:
  Worker0:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref RhcosAmi
      BlockDeviceMappings:
      - DeviceName: /dev/xvda
        Ebs:
          VolumeSize: "120"
          VolumeType: "gp2"
      IamInstanceProfile: !Ref WorkerInstanceProfileName
      InstanceType: !Ref WorkerInstanceType
      NetworkInterfaces:
      - AssociatePublicIpAddress: "false"
        DeviceIndex: "0"
        GroupSet:
        - !Ref "WorkerSecurityGroupId"
        SubnetId: !Ref "Subnet"
      UserData:
        Fn::Base64: !Sub
        - '{"ignition":{"config":{"merge":[{"source":"${SOURCE}"}]},"security":{"tls":{"certificateAuthorities":[{"source":"${CA_BUNDLE}"}]}},"version":"3.1.0"}}'
        - {
          SOURCE: !Ref IgnitionLocation,
          CA_BUNDLE: !Ref CertificateAuthorities,
        }
      Tags:
      - Key: !Join ["", ["kubernetes.io/cluster/", !Ref InfrastructureName]]
        Value: "shared"

Outputs:
  PrivateIP:
    Description: The compute node private IP address.
    Value: !GetAtt Worker0.PrivateIp

4.4.11.2. Creating the CloudFormation stack for compute machines

You can create a stack of Amazon Web Services (AWS) resources for the compute machines by using the provided CloudFormation template.

Important

When you use the CloudFormation template for the control plane machines, the template provisions all three control plane machines with a single stack; however, when you use the CloudFormation template to deploy the compute machines, you must create the number of stacks based on the number that you defined in the install-config.yaml file. You provision each stack once for each machine. To provision a new compute machine, you must change the stack name.

Procedure

  • To create the CloudFormation stack for compute machines, run the following command:

    $ aws cloudformation create-stack --stack-name <name> \
         --template-body file://<template>.yaml \
         --parameters file://<parameters>.json

    where:

    <name>
    Specifies the <name> with the name for the CloudFormation stack, such as cluster-worker-1. You need the name of this stack if you remove the cluster.
    <template>
    Specifies the relative path and the name of the CloudFormation template YAML file that you saved.
    <parameters>

    Specifies the relative path and the name of the JSON file for the CloudFormation parameters.

    Example output

    arn:aws:cloudformation:us-east-1:269333783861:stack/cluster-worker-1/729ee301-1c2a-11eb-348f-sd9888c65b59

After creating all required infrastructure in AWS, you can start the bootstrap sequence that initializes the OpenShift Container Platform control plane. Run the installation program to monitor the bootstrap process until the control plane is ready.

Prerequisites

  • You created the worker nodes.

Procedure

  1. Change to the directory that has the installation program and start the bootstrap process that initializes the OpenShift Container Platform control plane:

    $ ./openshift-install wait-for bootstrap-complete --dir <installation_directory> \
        --log-level=info
    • For <installation_directory>, specify the path to the directory that you stored the installation files in.
    • To view different installation details, specify warn, debug, or error instead of info.

      Example output

      INFO Waiting up to 20m0s for the Kubernetes API at https://api.mycluster.example.com:6443...
      INFO API v1.34.2 up
      INFO Waiting up to 45m0s for bootstrapping to complete...
      INFO It is now safe to remove the bootstrap resources
      INFO Time elapsed: 1s

      The bootstrapping completion wait time varies per platform.

      If the command exits without a FATAL warning, your OpenShift Container Platform control plane has initialized.

      Note

      After the control plane initializes, it sets up the compute nodes and installs additional services in the form of Operators.

4.4.13. Approve the certificate signing requests for your machines

To allow newly added machines to join your OpenShift Container Platform cluster, confirm that the cluster approves pending certificate signing requests (CSRs), or approve them yourself. Approve client requests first, then server requests.

Prerequisites

  • You added machines to your cluster.

Procedure

  1. Confirm that the cluster recognizes the machines:

    $ oc get nodes

    Example output

    NAME      STATUS    ROLES   AGE  VERSION
    master-0  Ready     master  63m  v1.34.2
    master-1  Ready     master  63m  v1.34.2
    master-2  Ready     master  64m  v1.34.2

    The output lists all of the machines that you created.

    Note

    The preceding output might not include the compute nodes until you approve some CSRs.

  2. Review the pending CSRs and ensure that you see the client requests with the Pending or Approved status for each machine that you added to the cluster:

    $ oc get csr

    Example output

    NAME        AGE     REQUESTOR                                                                   CONDITION
    csr-8b2br   15m     system:serviceaccount:openshift-machine-config-operator:node-bootstrapper   Pending
    csr-8vnps   15m     system:serviceaccount:openshift-machine-config-operator:node-bootstrapper   Pending
    ...

    In this example, two machines are joining the cluster. You might see more approved CSRs in the list.

  3. If the CSRs were not approved, after all of the pending CSRs for the machines you added are in Pending status, approve the CSRs for your cluster machines:

    Note

    You must approve your CSRs within an hour of adding the machines to the cluster. If you do not approve them within an hour, the certificates rotate, and more than two certificates are present for each node. You must approve all of these certificates. After you approve the client CSR, the kubelet creates a secondary CSR for the serving certificate, which requires manual approval. The machine-approver then automatically approves later serving certificate renewal requests if the kubelet requests a new certificate with the same parameters.

    Note

    For clusters running on platforms that are not machine API enabled, such as bare metal and other user-provisioned infrastructure, you must implement a method of automatically approving the kubelet serving certificate requests (CSRs). If you do not approve a request, the oc exec, oc rsh, and oc logs commands cannot succeed, because the API server requires a serving certificate when it connects to the kubelet. Any operation that contacts the kubelet endpoint requires this certificate approval to be in place. The method must watch for new CSRs, confirm that the node-bootstrapper service account in the system:node or system:admin groups submitted the CSR, and confirm the identity of the node.

    • To approve them individually, run the following command for each valid CSR:

      $ oc adm certificate approve <csr_name>

      where:

      <csr_name>
      Specifies the name of a CSR from the list of current CSRs.
    • To approve all pending CSRs, run the following command:

      $ oc get csr -o go-template='{{range .items}}{{if not .status}}{{.metadata.name}}{{"\n"}}{{end}}{{end}}' | xargs --no-run-if-empty oc adm certificate approve
      Note

      Some Operators might not become available until you approve some CSRs.

  4. After you approve your client requests, review the server requests for each machine that you added to the cluster:

    $ oc get csr

    Example output

    NAME        AGE     REQUESTOR                                                                   CONDITION
    csr-bfd72   5m26s   system:node:ip-10-0-50-126.us-east-2.compute.internal                       Pending
    csr-c57lv   5m26s   system:node:ip-10-0-95-157.us-east-2.compute.internal                       Pending
    ...

  5. If the remaining CSRs are not approved, and are in the Pending status, approve the CSRs for your cluster machines:

    • To approve them individually, run the following command for each valid CSR:

      $ oc adm certificate approve <csr_name>

      where:

      <csr_name>
      Specifies the name of a CSR from the list of current CSRs.
    • To approve all pending CSRs, run the following command:

      $ oc get csr -o go-template='{{range .items}}{{if not .status}}{{.metadata.name}}{{"\n"}}{{end}}{{end}}' | xargs oc adm certificate approve
  6. After you approve all client and server CSRs, the machines have the Ready status. Verify this by running the following command:

    $ oc get nodes

    Example output

    NAME      STATUS    ROLES   AGE  VERSION
    master-0  Ready     master  73m  v1.34.2
    master-1  Ready     master  73m  v1.34.2
    master-2  Ready     master  74m  v1.34.2
    worker-0  Ready     worker  11m  v1.34.2
    worker-1  Ready     worker  11m  v1.34.2

    Note

    You might need to wait a few minutes after approval of the server CSRs for the machines to reach the Ready status.

4.4.14. Initial Operator configuration

After the control plane initializes, you must immediately configure some Operators so that they all become available.

Prerequisites

  • Your control plane has initialized.

Procedure

  1. Watch the cluster components come online:

    $ watch -n5 oc get clusteroperators

    Example output

    NAME                                       VERSION   AVAILABLE   PROGRESSING   DEGRADED   SINCE
    authentication                             4.21.0    True        False         False      19m
    baremetal                                  4.21.0    True        False         False      37m
    cloud-credential                           4.21.0    True        False         False      40m
    cluster-autoscaler                         4.21.0    True        False         False      37m
    config-operator                            4.21.0    True        False         False      38m
    console                                    4.21.0    True        False         False      26m
    csi-snapshot-controller                    4.21.0    True        False         False      37m
    dns                                        4.21.0    True        False         False      37m
    etcd                                       4.21.0    True        False         False      36m
    image-registry                             4.21.0    True        False         False      31m
    ingress                                    4.21.0    True        False         False      30m
    insights                                   4.21.0    True        False         False      31m
    kube-apiserver                             4.21.0    True        False         False      26m
    kube-controller-manager                    4.21.0    True        False         False      36m
    kube-scheduler                             4.21.0    True        False         False      36m
    kube-storage-version-migrator              4.21.0    True        False         False      37m
    machine-api                                4.21.0    True        False         False      29m
    machine-approver                           4.21.0    True        False         False      37m
    machine-config                             4.21.0    True        False         False      36m
    marketplace                                4.21.0    True        False         False      37m
    monitoring                                 4.21.0    True        False         False      29m
    network                                    4.21.0    True        False         False      38m
    node-tuning                                4.21.0    True        False         False      37m
    openshift-apiserver                        4.21.0    True        False         False      32m
    openshift-controller-manager               4.21.0    True        False         False      30m
    openshift-samples                          4.21.0    True        False         False      32m
    operator-lifecycle-manager                 4.21.0    True        False         False      37m
    operator-lifecycle-manager-catalog         4.21.0    True        False         False      37m
    operator-lifecycle-manager-packageserver   4.21.0    True        False         False      32m
    service-ca                                 4.21.0    True        False         False      38m
    storage                                    4.21.0    True        False         False      37m

  2. Configure the Operators that are not available.

4.4.14.1. Disabling the default software catalog sources

To use only trusted or locally available Operator catalogs, disable the default software catalog sources that OpenShift Container Platform configures during installation. In a restricted network environment, you must disable the default catalogs as a cluster administrator.

Procedure

  • Disable the sources for the default catalogs by adding disableAllDefaultSources: true to the OperatorHub object:

    $ oc patch OperatorHub cluster --type json \
        -p '[{"op": "add", "path": "/spec/disableAllDefaultSources", "value": true}]'
    Tip

    Or, you can use the web console to manage catalog sources. From the Administration Cluster Settings Configuration OperatorHub page, click the Sources tab, where you can create, update, delete, disable, and enable individual sources.

4.4.14.2. Image registry storage configuration

Amazon Web Services provides default storage, which means the Image Registry Operator is available after installation. However, if the Registry Operator cannot create an S3 bucket and automatically configure storage, you must manually configure registry storage.

Configure a persistent volume, which is required for production clusters. Where applicable, you can configure an empty directory as the storage location for non-production clusters.

You can also allow the image registry to use block storage types by using the Recreate rollout strategy during upgrades.

If the Registry Operator cannot automatically create and configure an Amazon S3 bucket during installation, you must manually configure registry storage for your cluster.

Warning

To secure your registry images in Amazon Web Services (AWS), block public access to the S3 bucket.

Prerequisites

  • You have a cluster on AWS with user-provisioned infrastructure.
  • For Amazon S3 storage, the secret must contain two keys:

    • REGISTRY_STORAGE_S3_ACCESSKEY
    • REGISTRY_STORAGE_S3_SECRETKEY

Procedure

  1. Set up a Bucket Lifecycle Policy to cancel incomplete multipart uploads that are one day old.
  2. Enter the storage configuration in configs.imageregistry.operator.openshift.io/cluster:

    $ oc edit configs.imageregistry.operator.openshift.io/cluster

    Example configuration

    apiVersion: imageregistry.operator.openshift.io/v1
    kind: Config
    metadata:
      name: cluster
    spec:
      storage:
        s3:
          bucket: <bucket_name>
          region: <region_name>

You must configure storage for the Image Registry Operator. For non-production clusters, you can set the image registry to an empty directory, but you lose all images if you restart the registry.

Procedure

  • To set the image registry storage to an empty directory:

    $ oc patch configs.imageregistry.operator.openshift.io cluster --type merge --patch '{"spec":{"storage":{"emptyDir":{}}}}'
    Warning

    Configure this option only for non-production clusters.

    If you run this command before the Image Registry Operator initializes its components, the oc patch command fails with the following error:

    Example output

    Error from server (NotFound): configs.imageregistry.operator.openshift.io "cluster" not found

    Wait a few minutes and run the command again.

4.4.15. Deleting the bootstrap resources

After completing the initial Operator configuration for your OpenShift Container Platform cluster, you can delete the bootstrap resources from AWS to free up capacity and reduce costs.

Prerequisites

  • You completed the initial Operator configuration for your cluster.

Procedure

  1. Delete the bootstrap resources. If you used the CloudFormation template, delete its stack:

    • Delete the stack by using the AWS CLI:

      $ aws cloudformation delete-stack --stack-name <name>

      <name> is the name of your bootstrap stack.

    • Delete the stack by using the AWS CloudFormation console.

4.4.16. Creating the Ingress DNS records

If you removed the DNS zone configuration during installation, you must manually create DNS records that point to the Ingress load balancer so that your OpenShift Container Platform cluster routes are reachable.

You can create either a wildcard record or specific records. While the following procedure uses A records, you can use other record types that you require, such as CNAME or alias.

Prerequisites

Procedure

  1. Find the routes to create.

    • To create a wildcard record, use *.apps.<cluster_name>.<domain_name>, where <cluster_name> is your cluster name, and <domain_name> is the Route 53 base domain for your OpenShift Container Platform cluster.
    • To create specific records, you must create a record for each route that your cluster uses, as shown in the output of the following command:

      $ oc get --all-namespaces -o jsonpath='{range .items[*]}{range .status.ingress[*]}{.host}{"\n"}{end}{end}' routes

      Example output

      oauth-openshift.apps.<cluster_name>.<domain_name>
      console-openshift-console.apps.<cluster_name>.<domain_name>
      downloads-openshift-console.apps.<cluster_name>.<domain_name>
      alertmanager-main-openshift-monitoring.apps.<cluster_name>.<domain_name>
      prometheus-k8s-openshift-monitoring.apps.<cluster_name>.<domain_name>

  2. Retrieve the Ingress Operator load balancer status and note the value of the external IP address that it uses, which the EXTERNAL-IP column displays:

    $ oc -n openshift-ingress get service router-default

    Example output

    NAME             TYPE           CLUSTER-IP      EXTERNAL-IP                            PORT(S)                      AGE
    router-default   LoadBalancer   172.30.62.215   ab3...28.us-east-2.elb.amazonaws.com   80:31499/TCP,443:30693/TCP   5m

  3. Locate the hosted zone ID for the load balancer:

    $ aws elb describe-load-balancers | jq -r '.LoadBalancerDescriptions[] | select(.DNSName == "<external_ip>").CanonicalHostedZoneNameID'

    For <external_ip>, specify the value of the external IP address of the Ingress Operator load balancer that you obtained.

    Example output

    Z3AADJGX6KTTL2

    The output of this command is the load balancer hosted zone ID.

  4. Obtain the public hosted zone ID for your cluster’s domain:

    $ aws route53 list-hosted-zones-by-name \
                --dns-name "<domain_name>" \
                --query 'HostedZones[? Config.PrivateZone != `true` && Name == `<domain_name>.`].Id'
                --output text

    For <domain_name>, specify the Route 53 base domain for your OpenShift Container Platform cluster.

    Example output

    /hostedzone/Z3URY6TWQ91KVV

    The command output displays the public hosted zone ID for your domain. In this example, it is Z3URY6TWQ91KVV.

  5. Add the alias records to your private zone:

    $ aws route53 change-resource-record-sets --hosted-zone-id "<private_hosted_zone_id>" --change-batch '{
    >   "Changes": [
    >     {
    >       "Action": "CREATE",
    >       "ResourceRecordSet": {
    >         "Name": "\\052.apps.<cluster_domain>",
    >         "Type": "A",
    >         "AliasTarget":{
    >           "HostedZoneId": "<hosted_zone_id>",
    >           "DNSName": "<external_ip>.",
    >           "EvaluateTargetHealth": false
    >         }
    >       }
    >     }
    >   ]
    > }'

    where:

    <private_hosted_zone_id>
    Specifies the value from the output of the CloudFormation template for DNS and load balancing.
    <cluster_domain>
    Specifies the domain or subdomain that you use with your OpenShift Container Platform cluster.
    <hosted_zone_id>
    Specifies the public hosted zone ID for the load balancer that you obtained.
    <external_ip>
    Specifies the value of the external IP address of the Ingress Operator load balancer. Ensure that you include the trailing period (.) in this parameter value.
  6. Add the records to your public zone:

    $ aws route53 change-resource-record-sets --hosted-zone-id "<public_hosted_zone_id>"" --change-batch '{
    >   "Changes": [
    >     {
    >       "Action": "CREATE",
    >       "ResourceRecordSet": {
    >         "Name": "\\052.apps.<cluster_domain>",
    >         "Type": "A",
    >         "AliasTarget":{
    >           "HostedZoneId": "<hosted_zone_id>",
    >           "DNSName": "<external_ip>.",
    >           "EvaluateTargetHealth": false
    >         }
    >       }
    >     }
    >   ]
    > }'

    where: <public_hosted_zone_id>:: Specifies the public hosted zone for your domain. <cluster_domain>:: Specifies the domain or subdomain that you use with your OpenShift Container Platform cluster. <hosted_zone_id>:: Specifies the public hosted zone ID for the load balancer that you obtained. <external_ip>:: Specifies the value of the external IP address of the Ingress Operator load balancer. Ensure that you include the trailing period (.) in this parameter value.

To finish installing OpenShift Container Platform on user-provisioned AWS infrastructure, monitor the deployment until it completes successfully.

Prerequisites

  • You removed the bootstrap node for an OpenShift Container Platform cluster on user-provisioned AWS infrastructure.
  • You installed the oc CLI.

Procedure

  1. From the directory that has the installation program, complete the cluster installation:

    $ ./openshift-install --dir <installation_directory> wait-for install-complete

    For <installation_directory>, specify the path to the directory that you stored the installation files in.

    Example output

    INFO Waiting up to 40m0s for the cluster at https://api.mycluster.example.com:6443 to initialize...
    INFO Waiting up to 10m0s for the openshift-console route to be created...
    INFO Install complete!
    INFO To access the cluster as the system:admin user when using 'oc', run 'export KUBECONFIG=/home/myuser/install_dir/auth/kubeconfig'
    INFO Access the OpenShift web-console here: https://console-openshift-console.apps.mycluster.example.com
    INFO Login to the console with user: "kubeadmin", and password: "password"
    INFO Time elapsed: 1s

    Important
    • The Ignition config files that the installation program generates contain certificates that expire after 24 hours, which are then renewed at that time. If you shut down the cluster before renewing the certificates and later restart it after the 24 hours have elapsed, the cluster automatically recovers the expired certificates. The exception is that you must manually approve the pending node-bootstrapper certificate signing requests (CSRs) to recover kubelet certificates. See the documentation for Recovering from expired control plane certificates for more information.
    • Use Ignition config files within 12 hours after the installation program generates them because the 24-hour certificate rotates from 16 to 22 hours after you install the cluster. By using the Ignition config files within 12 hours, you can avoid installation failure if the certificate update runs during installation.
  2. Register your cluster on the Cluster registration page.

4.4.18. Logging in to the cluster by using the CLI

To log in to your cluster as the default system user, export the kubeconfig file. This configuration enables the CLI to authenticate and connect to the specific API server created during OpenShift Container Platform installation.

The kubeconfig file is specific to a cluster and OpenShift Container Platform generates it during installation.

Prerequisites

  • You deployed an OpenShift Container Platform cluster.
  • You installed the OpenShift CLI (oc).

Procedure

  1. Export the kubeadmin credentials by running the following command:

    $ export KUBECONFIG=<installation_directory>/auth/kubeconfig

    where:

    <installation_directory>
    Specifies the path to the directory that stores the installation files.
  2. Verify you can run oc commands successfully using the exported configuration by running the following command:

    $ oc whoami

    Example output

    system:admin

Next steps

  • "Customize your cluster"
  • "Remote health reporting"

4.4.19. Logging in to the cluster by using the web console

To verify that your cluster deployed successfully and access its features, log in to the OpenShift Container Platform web console as the kubeadmin user.

Prerequisites

  • You have access to the installation host.
  • You completed a cluster installation and all cluster Operators are available.

Procedure

  1. Obtain the password for the kubeadmin user from the kubeadmin-password file on the installation host:

    $ cat <installation_directory>/auth/kubeadmin-password
    Note

    Or, you can obtain the kubeadmin password from the <installation_directory>/.openshift_install.log log file on the installation host.

  2. List the OpenShift Container Platform web console route:

    $ oc get routes -n openshift-console | grep 'console-openshift'
    Note

    Or, you can obtain the OpenShift Container Platform route from the <installation_directory>/.openshift_install.log log file on the installation host.

    Example output

    console     console-openshift-console.apps.<cluster_name>.<base_domain>            console     https   reencrypt/Redirect   None

  3. Navigate to the route detailed in the output of the preceding command in a web browser and log in as the kubeadmin user.

To run workloads across x86_64 and ARM nodes, you can install an OpenShift Container Platform cluster on Amazon Web Services (AWS) with multi-architecture compute machine support.

Note

When you have nodes with multiple architectures in your cluster, the architecture of your image must be consistent with the architecture of the node. You must ensure that the pod is assigned to the node with the appropriate architecture and that it matches the image architecture.

You can install an AWS cluster with the support for configuring multi-architecture compute machines. After installing the AWS cluster, you can add multi-architecture compute machines to the cluster in the following ways:

  • Adding 64-bit x86 compute machines to a cluster that uses 64-bit ARM control plane machines and already includes 64-bit ARM compute machines. In this case, 64-bit x86 is the secondary architecture.
  • Adding 64-bit ARM compute machines to a cluster that uses 64-bit x86 control plane machines and already includes 64-bit x86 compute machines. In this case, 64-bit ARM is the secondary architecture.
Note

Before adding a secondary architecture node to your cluster, it is recommended to install the Multiarch Tuning Operator, and deploy a ClusterPodPlacementConfig custom resource. For more information, see "Managing workloads on multi-architecture clusters by using the Multiarch Tuning Operator".

4.5.1. Installing a cluster with multi-architecture support

You can install a cluster with multi-architecture support to use compute machines with different Central Processing Unit (CPU) architectures. Modifying your configuration file helps ensure your control plane and worker nodes deploy with the correct architecture.

Prerequisites

  • You installed the OpenShift CLI (oc).
  • You have the OpenShift Container Platform installation program.
  • You downloaded the pull secret for your cluster.

Procedure

  1. Check that the openshift-install binary is using the multi payload by running the following command:

    $ ./openshift-install version

    Example output

    ./openshift-install 4.21.0
    built from commit abc123etc
    release image quay.io/openshift-release-dev/ocp-release@sha256:abc123wxyzetc
    release architecture multi
    default architecture amd64

    The output must contain release architecture multi to indicate that the openshift-install binary is using the multi payload.

  2. Update the install-config.yaml file to configure the architecture for the nodes.

    Sample install-config.yaml file with multi-architecture configuration

    apiVersion: v1
    baseDomain: example.openshift.com
    compute:
    - architecture: amd64
      hyperthreading: Enabled
      name: worker
      platform: {}
      replicas: 3
    controlPlane:
      architecture: arm64
      name: master
      platform: {}
      replicas: 3
    # ...

    where:

    compute.architecture
    Specifies the architecture of the worker node. You can set this field to either arm64 or amd64.
    controlPlane.architecture
    Specifies the control plane node architecture. You can set this field to either arm64 or amd64.
Red Hat logoGithubRedditYoutubeTwitter

Lernen

Testen, kaufen und verkaufen

Communitys

Über Red Hat

Wir liefern gehärtete Lösungen, die es Unternehmen leichter machen, plattform- und umgebungsübergreifend zu arbeiten, vom zentralen Rechenzentrum bis zum Netzwerkrand.

Mehr Inklusion in Open Source

Red Hat hat sich verpflichtet, problematische Sprache in unserem Code, unserer Dokumentation und unseren Web-Eigenschaften zu ersetzen. Weitere Einzelheiten finden Sie in Red Hat Blog.

Über Red Hat Dokumentation

Legal Notice

Theme

© 2026 Red Hat
Nach oben