Tutorials

Red Hat OpenShift Service on AWS 4

Red Hat OpenShift Service on AWS tutorials

Red Hat OpenShift Documentation Team

Abstract

Tutorials on creating your first Red Hat OpenShift Service on AWS (ROSA) cluster.

Chapter 1. Tutorials overview

Use the step-by-step tutorials from Red Hat experts to get the most out of your Managed OpenShift cluster.

Important

This content is authored by Red Hat experts but has not yet been tested on every supported configuration.

Chapter 2. Tutorial: Activate Red Hat OpenShift Service on AWS and link your account

Before deploying your first cluster, activate your Red Hat OpenShift Service on AWS subscription, link your AWS and Red Hat accounts, and select the correct billing account.

Important

If you have received a private offer for the product, make sure to proceed according to the instructions provided with the private offer before following this tutorial. The private offer is designed either for a case when the product is already activated, which replaces an active subscription, or for first time activations.

2.1. Enable the subscription and set up your AWS account

Activate Red Hat OpenShift Service on AWS on the AWS console page to enable billing and metering for the service.

Prerequisites

  • You are logged in to the Red Hat account that you want to associate with the AWS account that will activate the Red Hat OpenShift Service on AWS product subscription.

    The AWS account used for service billing can only be associated with a single Red Hat account. Typically, an AWS payer account is the one that is used to subscribe to Red Hat OpenShift Service on AWS and used for account linking and billing.

    All team members within the same Red Hat organization can use the linked AWS account for service billing while creating Red Hat OpenShift Service on AWS clusters.

Procedure

  1. Click the Get started button on Content from console.aws.amazon.com is not included.AWS console page:

    rosa get started

    If you have activated Red Hat OpenShift Service on AWS before but did not complete the process, you can click the button and complete the account linking as described in the following steps.

  2. Confirm that you want your contact information to be shared with Red Hat and enable the service:

    rosa enable 2

    You are not charged by enabling the service in this step. The connection is made for billing and metering that takes place only after you deploy your first cluster. This could take a few minutes.

  3. Verify that the process completed successfully by reviewing the confirmation message:

    rosa prereq enable 3
  4. Check the status of additional prerequisites on this verification page. If any prerequisites are not met, a corresponding message is shown. The following is an example of insufficient quotas in the selected region:

    rosa service quota 4
    • Click the Increase service quotas button or use the Learn more link to get more information about how to manage service quotas. In the case of insufficient quotas, note that quotas are region-specific. You can use the region switcher to re-run the quota check for any region you are interested in and then submit service quota increase requests as needed.
  5. Confirm that all the prerequisites are met:

    rosa prereq 5

    The Elastic Load Balancing (ELB) service-linked role is created for you automatically. You can click any of the small Info blue links to get context-sensitive help and resources.

2.2. Link AWS and Red Hat accounts and subscriptions

Link your AWS and Red Hat accounts to associate your Red Hat OpenShift Service on AWS subscription with a billing account.

Procedure

  1. Click the Continue to Red Hat button to proceed with account linking:

    rosa continue rh 6
  2. Log in to your Red Hat account, if prompted.

    rosa login rh account 7
    Note

    Your AWS account must be linked to a single Red Hat organization.

    • You can also register for a new Red Hat account or reset your password on this page.
    • Log in to the Red Hat account that you want to associate with the AWS account that has activated the Red Hat OpenShift Service on AWS product subscription.
    • The AWS account used for service billing can only be associated with a single Red Hat account. Typically, an AWS payer account is the one that is used to subscribe to Red Hat OpenShift Service on AWS and used for account linking and billing.
    • All team members within the same Red Hat organization can use the linked AWS account for service billing while creating Red Hat OpenShift Service on AWS clusters.
  3. Complete the Red Hat account linking after reviewing the terms and conditions.

    Note

    This step is available only if the AWS account was not linked to any Red Hat account before.

    This step is skipped if the AWS account is already linked to the user’s logged in Red Hat account.

    If the AWS account is linked to a different Red Hat account, an error is displayed. See Correcting Billing Account Information for HCP clusters for troubleshooting.

  4. On the Complete your account connection page, verify that the Red Hat and AWS account numbers are correct.

    rosa rh account connection 8
  5. Click the Connect accounts button if you agree with the service terms.

    If this is the first time you are using the Red Hat Hybrid Cloud Console, you must agree with the general managed services terms and conditions before creating the first cluster:

    rosa terms conditions 9

    Additional terms that need to be reviewed and accepted are shown after clicking the View Terms and Conditions button:

    rosa terms conditions 9 5

    Submit your agreement once you have reviewed any additional terms when prompted at this time.

  6. The Hybrid Cloud Console provides a confirmation that AWS account setup was completed and lists the prerequisites for cluster deployment:

    rosa cluster create 10

    The last section of this page shows cluster deployment options, either using the ROSA command-line interface (CLI) (rosa) or through the web console:

    rosa cli ui 12

2.3. Select the AWS billing account during cluster deployment using the CLI

When deploying your cluster using ROSA command-line interface (CLI) (rosa), you must select the correct AWS billing account for Red Hat OpenShift Service on AWS.

Prerequisites

Procedure

  1. Initiate the cluster deployment using the rosa create cluster command. You can click the copy button on the This content is not included.Set up Red Hat OpenShift Service on AWS console page and paste the command in your terminal. This launches the cluster creation process in interactive mode.

    rosa cli 15
    1. Optional: Add the --profile <profile_name> option to the rosa create cluster command to use a non-default profile from your ~/.aws/credentials file, for example:

      $ rosa create cluster --profile stage

      If no profile is specified, the default AWS CLI profile determines the AWS infrastructure profile into which the cluster is deployed.

  2. Specify the billing AWS account.

    rosa create cli billing 17
    • Only AWS accounts that are linked to the user’s logged in Red Hat account are shown.
    • The specified AWS account is charged for using the Red Hat OpenShift Service on AWS service.
    • An indicator shows if the Red Hat OpenShift Service on AWS contract is enabled or not enabled for a given AWS billing account.

      • If you select an AWS billing account that shows the Contract enabled label, on-demand consumption rates are charged only after the capacity of your pre-paid contract is consumed.
      • AWS accounts without the Contract enabled label are charged the applicable on-demand consumption rates.

2.4. Select the AWS billing account during cluster deployment using the web console

When deploying your cluster using OpenShift Cluster Manager, you must select the correct AWS billing account for Red Hat OpenShift Service on AWS.

Procedure

  1. To start creating a cluster, select Create with web interface of the introductory Set up Red Hat OpenShift Service on AWS page.

    rosa deploy ui 19
    Note

    Complete the prerequisites before starting the web console deployment process.

    The ROSA command-line interface (CLI) (rosa) is required for certain tasks, such as creating the account roles. If you are deploying Red Hat OpenShift Service on AWS for the first time, follow the CLI steps until running the rosa whoami command, before starting the web console deployment steps.

  2. Select the Hosted control plane option, then click Next.

    rosa deploy ui hcp 20
  3. In the next step Accounts and roles, specify the infrastructure AWS account, into which the Red Hat OpenShift Service on AWS cluster is deployed and where the resources are consumed and managed.

    rosa ui account 21
    • Click the How to associate a new AWS account, if you don’t see the account into which you want to deploy the Red Hat OpenShift Service on AWS cluster for detailed information on how to create or link account roles for this association.
    • The ROSA CLI is used for this.
    • If you are using multiple AWS accounts and have their profiles configured for the AWS CLI, you can use the --profile selector to specify the AWS profile when working with the ROSA CLI commands.
  4. Select the AWS billing account.

    rosa ui billing 22
    • Only AWS accounts that are linked to the user’s logged in Red Hat account are shown.
    • The specified AWS account is charged for using the Red Hat OpenShift Service on AWS service.
    • An indicator shows if the Red Hat OpenShift Service on AWS contract is enabled or not enabled for a given AWS billing account.

      • If you select an AWS billing account that shows the Contract enabled label, on-demand consumption rates are charged only after the capacity of your pre-paid contract is consumed.
      • AWS accounts without the Contract enabled label are charged the applicable on-demand consumption rates.

        Note

        The following steps past the billing AWS account selection are beyond the scope of this tutorial.

2.5. Additional resources

Chapter 3. Tutorial: Accept and share a private offer for Red Hat OpenShift Service on AWS

Accept a private offer for Red Hat OpenShift Service on AWS and share the offer entitlement with team members in your Red Hat organization to ensure they can use the offer for the clusters they provision.

Red Hat OpenShift Service on AWS costs are composed of the AWS infrastructure costs and the Red Hat OpenShift Service on AWS service costs. AWS infrastructure costs, such as the EC2 instances that are running the needed workloads, are charged to the AWS account where the infrastructure is deployed. Red Hat OpenShift Service on AWS service costs are charged to the AWS account specified as the "AWS billing account" when deploying a cluster.

The cost components can be billed to different AWS accounts. Detailed description of how the Red Hat OpenShift Service on AWS service cost and AWS infrastructure costs are calculated can be found on the "Pricing" page linked in the Additional resources.

3.1. Accept a private offer

Accept a private offer for Red Hat OpenShift Service on AWS by reviewing available offers and selecting a new offer or upgrading an existing one.

Prerequisites

  • You are logged in using the AWS account that was specified as the buyer. Attempting to access the offer using another AWS account produces a "Page not found" error message.

Procedure

  1. Open the private offer URL provided by the seller. You can only access the URL from the AWS account ID that was specified by the seller.
  2. On the Offer selection page, review Available offers. Options can include:

    1. A regular private offer that is pre-selected. This type of offer can be accepted only if Red Hat OpenShift Service on AWS was not activated before using the public offer or another private offer.

      rosa regular private offer
    2. A private offer that was created for an AWS account that previously activated Red Hat OpenShift Service on AWS using the public offer. The selected private offer is labeled as Upgrade and accepting this offer replaces the currently running contract for Red Hat OpenShift Service on AWS.

      rosa private offer selection selection screen
    3. If multiple offers are available, the public offer activated earlier is shown together with the newly provided agreement-based offer that is labeled as "Upgrade".

      rosa private offer selection dropdown
  3. Verify that your offer configuration is selected and review the offer details.

    Note

    Review the contract end date, the number of units included with the offer, and the payment schedule. In this example, 1 cluster and up to 3 nodes utilizing 4 vCPUs are included.

    rosa private offer details
  4. Optional: Content from docs.aws.amazon.com is not included.Add your own purchase order (PO) number to the subscription that is being purchased, so it is included on your subsequent AWS invoices. Also, check the "Additional usage fees" that are charged for any usage above the scope of the "New offer configuration details".

    Note

    Private offers have several available configurations.

    • It is possible that the private offer you are accepting is set up with a fixed future start date.
    • If you do not have another active Red Hat OpenShift Service on AWS subscription at the time of accepting the private offer, a public offer or an older private offer entitlement, accept the private offer itself and continue with the account linking and cluster deployment steps after the specified service start date.

    You must have an active Red Hat OpenShift Service on AWS entitlement to complete these steps. Service start dates are always reported in the UTC time zone

  5. Create or upgrade your contract.

    1. For private offers accepted by an AWS account that does not have Red Hat OpenShift Service on AWS activated yet and is creating the first contract for this service, click the Create contract button.

      rosa create contract button
    2. For agreement-based offers, click the Upgrade current contract button shown in Figures 4 and 6.

      rosa upgrade contract button
  6. Click Confirm.

    rosa private offer acceptance confirmation window
  7. If the accepted private offer service start date is set to be immediately following the offer acceptance, click the Set up your account button in the confirmation modal window.

    rosa subscription contfirmation
  8. If the accepted private offer has a future start date specified, return to the private offer page after the service start date, and click the Setup your account button to proceed with the Red Hat and AWS account linking.

    Note

    With no agreement active, the account linking described below is not triggered, the "Account setup" process can be done only after the "Service start date".

    These are always in UTC time zone.

3.2. Share a private offer

You can share a private offer with other team members within your Red Hat organization account.

Red Hat OpenShift Service on AWS entitlement is shared with other team members through your Red Hat organization account. All existing users in the same Red Hat organization can select the billing AWS account that accepted the private offer. You can This content is not included.manage users in your Red Hat organization, when logged in as the Red Hat organization administrator, and invite or create new users.

Procedure

  1. Click Set up your account to proceed to the AWS and Red Hat account linking step. At this time, you are already logged in with the AWS account that accepted the offer. Log in to a Red Hat account, if prompted.

    Note

    A Red Hat OpenShift Service on AWS private offer cannot be shared with AWS linked accounts through the AWS License Manager.

  2. Add any users that you want to deploy Red Hat OpenShift Service on AWS clusters. Check Common User Management Questions for more details about Red Hat account user management tasks.
  3. Verify that the already logged in Red Hat account includes all users that are meant to be Red Hat OpenShift Service on AWS cluster deployers benefiting from the accepted private offer.
  4. Verify that the Red Hat account number and the AWS account ID are the desired accounts that are to be linked. This linking is unique and a Red Hat account can be connected only with a single AWS (billing) account.

    rosa aws and red hat accounts connection
  5. To link the AWS account with another Red Hat account, log out from the Red Hat Hybrid Cloud Console before connecting the accounts. Repeat the step of setting the account by returning to the private offer URL that is already accepted.

    An AWS account can be connected with a single Red Hat account only. Once Red Hat and AWS accounts are connected, this cannot be changed by the user. If a change is needed, the user must create a support ticket.

  6. Agree to the terms and conditions and then click Connect accounts.

3.3. Select the AWS billing account

When deploying Red Hat OpenShift Service on AWS clusters, verify that end users select the AWS billing account that accepted the private offer.

Procedure

  • When using the web interface to deploy Red Hat OpenShift Service on AWS, verify that the AWS billing account drop-down is set to the AWS account that accepted the private offer if the purchased quota is intended for the cluster you are creating.

    • The associated AWS infrastructure account is typically set to the AWS account ID used by the administrator of the cluster that is being created.
    • This can be the same AWS account as the billing AWS account.
    • AWS resources are deployed into this account and all the billing associated with those resources is processed accordingly.
    • If different AWS accounts are selected as the infrastructure and billing accounts, an informative note is displayed.

      rosa infrastructure and billing aws account selection during rosa with hcp cluster deployment

3.4. Private offer troubleshooting

Review solutions for the most frequent issues associated with private offer acceptance and Red Hat account linking.

3.4.1. Accessing a private offer using a different AWS account

  • If you try accessing the private offer when logged in under an AWS account ID that is not defined in the offer, and see the "Page not found" message, then verify that you are logged in as the desired AWS billing account.

    rosa http 404 error when using the private offer url
    • Contact the seller if you need the private offer to be extended to another AWS account.

3.4.2. The private offer cannot be accepted because of an active subscription

  • If you try accessing a private offer that was created for the first-time Red Hat OpenShift Service on AWS activation, while you already have Red Hat OpenShift Service on AWS activated using another public or private offer, and see the following notice, then contact the seller who provided you with the offer.

    The seller can provide you with a new offer that will seamlessly replace your current agreement, without a need to cancel your previous subscription.

    rosa existing subscription preventing private offer acceptance

3.4.3. The AWS account is already linked to a different Red Hat account

  • If you see the error message "AWS account is already linked to a different Red Hat account" when you try to connect the AWS account that accepted the private offer with a presently logged-in Red Hat user, then the AWS account is already connected to another Red Hat user.

    rosa aws account is already linked to a different red hat account
  • You can either log in using another Red Hat account or another AWS account.

    • However, since this guide pertains to private offers, the assumption is that you are logged in with the AWS account that was specified as the buyer and already accepted the private offer so it is intended to be used as the billing account. Logging in as another AWS account is not expected after a private offer was accepted.
  • You can still log in with another Red Hat user which is already connected to the AWS account that accepted the private offer. Other Red Hat users belonging to the same Red Hat organization are able to use the linked AWS account as the Red Hat OpenShift Service on AWS AWS billing account when creating clusters.
  • If you believe that the existing account linking might not be correct, see the "My team members belong to different Red Hat organizations" question for tips on how you can proceed.

3.4.4. My team members belong to different Red Hat organizations

  • An AWS account can be connected to a single Red Hat account only. Any user that wants to create a cluster and benefit from the private offer granted to this AWS account needs to be in the same Red Hat account. This can be achieved by inviting the user to the same Red Hat account and creating a new Red Hat user.

3.4.5. Incorrect AWS billing account was selected when creating a cluster

  • If the user selected an incorrect AWS billing account, the fastest way to fix this is to delete the cluster and create a new one, while selecting the correct AWS billing account.
  • If this is a production cluster that cannot be easily deleted, contact Red Hat support to change the billing account for an existing cluster. Expect some turnaround time for this to be resolved.

3.5. Additional resources

Chapter 4. Tutorial: Deploy Red Hat OpenShift Service on AWS with a custom DNS resolver

Use a custom Dynamic Host Configuration Protocol (DHCP) option set to customize your Virtual Private Cloud (VPC) with your own Domain Name System (DNS) server, domain name, and more. Red Hat OpenShift Service on AWS clusters support using custom DHCP option sets.

By default, Red Hat OpenShift Service on AWS clusters require setting the "domain name servers" option to AmazonProvidedDNS to ensure successful cluster creation and operation. If you want to use custom DNS servers for DNS resolution, you must do additional configuration to ensure successful Red Hat OpenShift Service on AWS cluster creation and operation.

In this tutorial, you configure a DNS server to forward DNS lookups for specific DNS zones to an Amazon Route 53 Inbound Resolver. For more information, see Additional resources.

Note

This tutorial uses the open-source BIND DNS server (named) to demonstrate the configuration necessary to forward DNS lookups to an Amazon Route 53 Inbound Resolver located in the VPC you plan to deploy a Red Hat OpenShift Service on AWS cluster into. Refer to the documentation of your preferred DNS server for how to configure zone forwarding.

4.1. Set up your environment

You can use environment variables to ensure consistency across the commands within this lab.

Prerequisites

  • You have access to the ROSA command-line interface (CLI) (rosa).
  • You have access to the AWS CLI (aws).
  • You have manually created an AWS Virtual Private Cloud (VPC).
  • You have configured a DHCP option set to point to a custom DNS server and set as the default for your VPC.

Procedure

  1. In your terminal, configure the following environment variables:

    $ export VPC_ID=<vpc_ID>
    $ export REGION=<region>
    $ export VPC_CIDR=<vpc_CIDR>

    where:

    <vpc_ID>
    Replace with the ID of the VPC you want to install your cluster into.
    <region>
    Replace with the AWS region you want to install your cluster into.
    <vpc_CIDR>
    Replace with the CIDR range of your VPC.
  2. Ensure all fields output correctly before moving to the next section:

    $ echo "VPC ID: ${VPC_ID}, VPC CIDR Range: ${VPC_CIDR}, Region: ${REGION}"

4.2. Create an Amazon Route 53 Inbound Resolver

Deploy an Amazon Route 53 Inbound Resolver in the Virtual Private Cloud (VPC) where you plan to deploy the cluster. With the inbound resolver, your DNS server can forward queries to Route 53.

Warning

In this example, the Content from docs.aws.amazon.com is not included.Amazon Route 53 Inbound Resolver is deployed into the same VPC the cluster uses. If you want to deploy it into a separate VPC, you must manually associate the private hosted zone(s) once cluster creation is started. You cannot associate the zone before the cluster creation process begins. Failure to associate the private hosted zone during the cluster creation process will result in cluster creation failures.

Procedure

  1. Create a security group and allow access to ports 53/tcp and 53/udp from the VPC:

    $ SG_ID=$(aws ec2 create-security-group --group-name rosa-inbound-resolver --description "Security group for ROSA inbound resolver" --vpc-id ${VPC_ID} --region ${REGION} --output text)
    $ aws ec2 authorize-security-group-ingress --group-id ${SG_ID} --protocol tcp --port 53 --cidr ${VPC_CIDR} --region ${REGION}
    $ aws ec2 authorize-security-group-ingress --group-id ${SG_ID} --protocol udp --port 53 --cidr ${VPC_CIDR} --region ${REGION}
  2. Create an Amazon Route 53 Inbound Resolver in your VPC:

    $ RESOLVER_ID=$(aws route53resolver create-resolver-endpoint \
      --name rosa-inbound-resolver \
      --creator-request-id rosa-$(date '+%Y-%m-%d') \
      --security-group-ids ${SG_ID} \
      --direction INBOUND \
      --ip-addresses $(aws ec2 describe-subnets --filter Name=vpc-id,Values=${VPC_ID} --region ${REGION} | jq -jr '.Subnets | map("SubnetId=\(.SubnetId) ") | .[]') \
      --region ${REGION} \
      --output text \
      --query 'ResolverEndpoint.Id')
    Note

    The above command attaches Amazon Route 53 Inbound Resolver endpoints to all subnets in the provided VPC using dynamically allocated IP addresses. If you prefer to manually specify the subnets, the IP addresses, or both, run the following command instead:

    $ RESOLVER_ID=$(aws route53resolver create-resolver-endpoint \
      --name rosa-inbound-resolver \
      --creator-request-id rosa-$(date '+%Y-%m-%d') \
      --security-group-ids ${SG_ID} \
      --direction INBOUND \
      --ip-addresses SubnetId=<subnet_ID>,Ip=<endpoint_IP> SubnetId=<subnet_ID>,Ip=<endpoint_IP> \
      --region ${REGION} \
      --output text \
      --query 'ResolverEndpoint.Id')

    + where:

    <subnet_ID>
    Specifies the subnet ID you want inbound resolver endpoints added to.
    <endpoint_IP>
    Specifies the static IP addresses you want inbound resolver endpoints added to.
  3. Get the IP addresses of your inbound resolver endpoints to configure in your DNS server configuration:

    $ aws route53resolver list-resolver-endpoint-ip-addresses \
      --resolver-endpoint-id ${RESOLVER_ID} \
      --region=${REGION} \
      --query 'IpAddresses[*].Ip'

    Example output

    [
        "10.0.45.253",
        "10.0.23.131",
        "10.0.148.159"
    ]

4.3. Configure your DNS server

Configure your Domain Name System (DNS) server to forward the private hosted zones to your Amazon Route 53 Inbound Resolver so the Red Hat OpenShift Service on AWS cluster can resolve internal DNS names after creation.

The following private hosted zones must be forwarded:

  • <cluster-name>.hypershift.local
  • rosa.<domain-prefix>.<unique-ID>.p3.openshiftapps.com

These Amazon Route 53 private hosted zones are created during cluster creation. The cluster-name and domain-prefix are customer-specified values, but the unique-ID is randomly generated during cluster creation and cannot be preselected. As such, you must wait for the cluster creation process to begin before configuring forwarding for the p3.openshiftapps.com private hosted zone.

Procedure

  1. Before the cluster is created, configure your DNS server to forward all DNS requests for <cluster-name>.hypershift.local to your Amazon Route 53 Inbound Resolver endpoints.

    If you use a BIND DNS server, add a new zone to the /etc/named.conf file using the following example:

    zone "<cluster-name>.hypershift.local" {
      type forward;
      forward only;
      forwarders {
        10.0.45.253;
        10.0.23.131;
        10.0.148.159;
      };
    };
    • Replace <cluster-name> with your Red Hat OpenShift Service on AWS cluster name.
    • Replace with the IP addresses of your inbound resolver endpoints collected above, ensuring that following each IP address there is a ;.
  2. Create your cluster.
  3. After your cluster has begun the creation process, locate the newly created private hosted zone:

    $ aws route53 list-hosted-zones-by-vpc \
      --vpc-id ${VPC_ID} \
      --vpc-region ${REGION} \
      --query 'HostedZoneSummaries[*].Name' \
      --output table

    Example output

    --------------------------------------------------
    |             ListHostedZonesByVPC               |
    +------------------------------------------------+
    |  rosa.domain-prefix.lkmb.p3.openshiftapps.com. |
    |  cluster-name.hypershift.local.                |
    +------------------------------------------------+

    Note

    It may take a few minutes for the cluster creation process to create the private hosted zones in Route 53. If you do not see a p3.openshiftapps.com domain, wait a few minutes and run the command again.

  4. When you know the unique ID of the cluster domain, configure your DNS server to forward all DNS requests for rosa.<domain-prefix>.<unique-ID>.p3.openshiftapps.com to your Amazon Route 53 Inbound Resolver endpoints. If you use a BIND DNS server, add a new zone to the /etc/named.conf file using the following example:

    zone "rosa.<domain-prefix>.<unique-ID>.p3.openshiftapps.com" {
      type forward;
      forward only;
      forwarders {
        10.0.45.253;
        10.0.23.131;
        10.0.148.159;
      };
    };
    • Replace <domain-prefix> with your cluster domain prefix and <unique-ID> with your unique ID collected above.
    • Replace with the IP addresses of your inbound resolver endpoints collected above, ensuring that following each IP address there is a ;.

4.4. Additional resources

Chapter 5. Tutorial: Use AWS WAF and Amazon CloudFront to protect Red Hat OpenShift Service on AWS workloads

You can use AWS Web Application Firewall (WAF) to monitor HTTP and HTTPS requests that are forwarded to your protected web application resources.

You can use an Amazon CloudFront to add a WAF to your Red Hat OpenShift Service on AWS workloads. Using an external solution protects Red Hat OpenShift Service on AWS resources from experiencing denial of service due to handling the WAF.

Note

WAFv1, WAF classic, is no longer supported. Use WAFv2.

5.1. Set up your environment

You can use environment variables to ensure consistency across the commands within this lab.

Prerequisites

  • You have created a Red Hat OpenShift Service on AWS cluster.
  • You have access to the OpenShift CLI (oc).
  • You have access to the AWS CLI (aws).

Procedure

  1. In your terminal, configure the following environment variables:

    $ export DOMAIN=apps.example.com
    $ export AWS_PAGER=""
    $ export CLUSTER_NAME=$(oc get infrastructure cluster -o=jsonpath="{.status.infrastructureName}"  | sed 's/-[a-z0-9]\{5\}$//')
    $ export REGION=$(oc get infrastructure cluster -o=jsonpath="{.status.platformStatus.aws.region}")
    $ export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
    $ export SCRATCH="/tmp/${CLUSTER}/cloudfront-waf"
    $ mkdir -p ${SCRATCH}
    $ echo "Cluster: ${CLUSTER}, Region: ${REGION}, AWS Account ID: ${AWS_ACCOUNT_ID}"
  2. Replace the DOMAIN value apps.example.com with the custom domain you want to use for the IngressController.

    Note

    The "Cluster" output from the previous command might be the name of your cluster, the internal ID of your cluster, or the cluster’s domain prefix. If you prefer to use another identifier, you can manually set this value by running the following command:

    $ export CLUSTER=my-custom-value

5.2. Set up the secondary ingress controller

You must configure a secondary ingress controller to segment your external Web Application Firewall (WAF)-protected traffic from your standard and default cluster ingress controller.

Prerequisites

  • You have a publicly trusted Subject Alternative Name (SAN) or wildcard certificate for your custom domain, such as CN=*.apps.example.com

    Important

    Amazon CloudFront uses HTTPS to communicate with your cluster’s secondary ingress controller. As explained in the Content from docs.aws.amazon.com is not included.Amazon CloudFront documentation, you cannot use a self-signed certificate for HTTPS communication between CloudFront and your cluster. Amazon CloudFront verifies that the certificate was issued by a trusted certificate authority.

Procedure

  1. Create a new Transport Layer Security (TLS) secret from a private key and a public certificate, where fullchain.pem is your full wildcard certificate chain, including any intermediaries, and privkey.pem is your wildcard certificate’s private key.

    Example

    $ oc -n openshift-ingress create secret tls waf-tls --cert=fullchain.pem --key=privkey.pem

  2. Create a new IngressController resource, for example, a waf-ingress-controller.yaml:

    apiVersion: operator.openshift.io/v1
    kind: IngressController
    metadata:
      name: cloudfront-waf
      namespace: openshift-ingress-operator
    spec:
      domain: apps.example.com
      defaultCertificate:
        name: waf-tls
      endpointPublishingStrategy:
        loadBalancer:
          dnsManagementPolicy: Unmanaged
          providerParameters:
            aws:
              type: NLB
            type: AWS
          scope: External
        type: LoadBalancerService
      routeSelector:
        matchLabels:
         route: waf

    where:

    domain: apps.example.com
    Specifies the custom domain you want to use for the IngressController.
    routeSelector
    Filters the set of routes serviced by the Ingress Controller. If you don’t provide a value, no filtering occurs. In this tutorial, you use the waf route selector.
  3. Apply the IngressController:

    Example

    $ oc apply -f waf-ingress-controller.yaml

Verification

  • Verify that your IngressController has successfully created an external load balancer:

    $ oc -n openshift-ingress get service/router-cloudfront-waf

    Example output

    NAME                    TYPE           CLUSTER-IP      EXTERNAL-IP                                                                     PORT(S)                      AGE
    router-cloudfront-waf   LoadBalancer   172.30.16.141   a68a838a7f26440bf8647809b61c4bc8-4225395f488830bd.elb.us-east-1.amazonaws.com   80:30606/TCP,443:31065/TCP   2m19s

5.3. Configure the AWS WAF

Create AWS Web Application Firewall (WAF) rules and a web access control list (ACL) to monitor, protect, and control the HTTP and HTTPS requests that are forwarded to your Red Hat OpenShift Service on AWS workloads.

Procedure

  1. Create an AWS WAF rules file to apply to an ACL:

    $ cat << EOF > ${SCRATCH}/waf-rules.json
    [
        {
          "Name": "AWS-AWSManagedRulesCommonRuleSet",
          "Priority": 0,
          "Statement": {
            "ManagedRuleGroupStatement": {
              "VendorName": "AWS",
              "Name": "AWSManagedRulesCommonRuleSet"
            }
          },
          "OverrideAction": {
            "None": {}
          },
          "VisibilityConfig": {
            "SampledRequestsEnabled": true,
            "CloudWatchMetricsEnabled": true,
            "MetricName": "AWS-AWSManagedRulesCommonRuleSet"
          }
        },
        {
          "Name": "AWS-AWSManagedRulesSQLiRuleSet",
          "Priority": 1,
          "Statement": {
            "ManagedRuleGroupStatement": {
              "VendorName": "AWS",
              "Name": "AWSManagedRulesSQLiRuleSet"
            }
          },
          "OverrideAction": {
            "None": {}
          },
          "VisibilityConfig": {
            "SampledRequestsEnabled": true,
            "CloudWatchMetricsEnabled": true,
            "MetricName": "AWS-AWSManagedRulesSQLiRuleSet"
          }
        }
    ]
    EOF

    This enables the Core (Common) and SQL AWS Managed Rule Sets.

  2. Create an AWS WAF Web ACL using the rules you specified in the previous step:

    $ WAF_WACL=$(aws wafv2 create-web-acl \
      --name cloudfront-waf \
      --region ${REGION} \
      --default-action Allow={} \
      --scope CLOUDFRONT \
      --visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=${CLUSTER}-waf-metrics \
      --rules file://${SCRATCH}/waf-rules.json \
      --query 'Summary.Name' \
      --output text)

5.4. Configure Amazon CloudFront

Create an Amazon CloudFront distribution that directs traffic through AWS Web Application Firewall (WAF) to protect your workloads.

Procedure

  1. Retrieve the newly created custom ingress controller’s Network Load Balancer (NLB) hostname:

    $ NLB=$(oc -n openshift-ingress get service router-cloudfront-waf \
      -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
  2. Import your certificate into Amazon Certificate Manager, where cert.pem is your wildcard certificate, fullchain.pem is your wildcard certificate’s chain and privkey.pem is your wildcard certificate’s private key.

    Note

    Regardless of what region your cluster is deployed, you must import this certificate to us-east-1 as Amazon CloudFront is a global AWS service.

    Example

    $ aws acm import-certificate --certificate file://cert.pem \
      --certificate-chain file://fullchain.pem \
      --private-key file://privkey.pem \
      --region us-east-1

  3. Log in to the Content from us-east-1.console.aws.amazon.com is not included.AWS console to create a CloudFront distribution.
  4. Configure the CloudFront distribution by using the following information:

    Note

    If an option is not specified in the table below, leave the default, even if it is blank.

    OptionValue

    Origin domain

    Output from the previous command [a]

    Name

    rosa-waf-ingress [b]

    Viewer protocol policy

    Redirect HTTP to HTTPS

    Allowed HTTP methods

    GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE

    Cache policy

    CachingDisabled

    Origin request policy

    AllViewer

    Web Application Firewall (WAF)

    Enable security protections

    Use existing WAF configuration

    true

    Choose a web ACL

    cloudfront-waf

    Alternate domain name (CNAME)

    *.apps.example.com [c]

    Custom SSL certificate

    Select the certificate you imported from the step above [d]

    1. Run echo ${NLB} to get the origin domain.
    2. If you have multiple clusters, ensure the origin name is unique.
    3. This should match the wildcard domain you used to create the custom ingress controller.
    4. This should match the alternate domain name entered above.
  5. Retrieve the Amazon CloudFront Distribution endpoint:

    $ aws cloudfront list-distributions --query "DistributionList.Items[?Origins.Items[?DomainName=='${NLB}']].DomainName" --output text
  6. Update the DNS of your custom wildcard domain with a CNAME to the Amazon CloudFront Distribution endpoint from the step above.

    Example

    *.apps.example.com CNAME d1b2c3d4e5f6g7.cloudfront.net

5.5. Deploy a sample application

Deploy a sample application by using the OpenShift CLI (oc) tool.

Procedure

  1. Create a new project for your sample application by running the following command:

    $ oc new-project hello-world
  2. Deploy a hello-world application:

    $ oc -n hello-world new-app --image=docker.io/openshift/hello-openshift
  3. Create a route for the application specifying your custom domain name:

    Example

    $ oc -n hello-world create route edge --service=hello-openshift hello-openshift-tls \
    --hostname hello-openshift.${DOMAIN}

  4. Label the route to admit it to your custom ingress controller:

    $ oc -n hello-world label route.route.openshift.io/hello-openshift-tls route=waf

5.6. Test the WAF

Verify that your AWS Web Application Firewall (WAF) configuration is working by sending valid and malicious requests to the sample application.

Procedure

  1. Test that the application is accessible behind Amazon CloudFront:

    Example

    $ curl "https://hello-openshift.${DOMAIN}"

    Example output

    Hello OpenShift!

  2. Test that the WAF denies a bad request:

    Example

    $ curl -X POST "https://hello-openshift.${DOMAIN}" \
      -F "user='<script><alert>Hello></alert></script>'"

    Example output

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
    <TITLE>ERROR: The request could not be satisfied</TITLE>
    </HEAD><BODY>
    <H1>403 ERROR</H1>
    <H2>The request could not be satisfied.</H2>
    <HR noshade size="1px">
    Request blocked.
    We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
    <BR clear="all">
    If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation.
    <BR clear="all">
    <HR noshade size="1px">
    <PRE>
    Generated by cloudfront (CloudFront)
    Request ID: nFk9q2yB8jddI6FZOTjdliexzx-FwZtr8xUQUNT75HThPlrALDxbag==
    </PRE>
    <ADDRESS>
    </ADDRESS>
    </BODY></HTML>

    The expected result is a 403 ERROR, which means the AWS WAF is protecting your application.

5.7. Additional resources

Chapter 6. Tutorial: Use AWS WAF and AWS ALBs to protect Red Hat OpenShift Service on AWS workloads

You can use AWS Web Application Firewall (WAF) to monitor HTTP and HTTPS requests that are forwarded to your protected web application resources.

You can use an AWS Application Load Balancer (ALB) to add a Web Application Firewall (WAF) to your Red Hat OpenShift Service on AWS workloads. Using an external solution protects Red Hat OpenShift Service on AWS resources from experiencing denial of service due to handling the WAF.

Important

It is recommended that you use the more flexible CloudFront method unless you absolutely must use an ALB-based solution. For more information, see Additional resources.

6.1. Set up your environment

You can use environment variables to ensure consistency across the commands within this lab.

Prerequisites

  • You have created a multiple availability zone (AZ) Red Hat OpenShift Service on AWS cluster.

    Note

    AWS ALBs require at least two public subnets across AZs, Content from docs.aws.amazon.com is not included.per the AWS documentation. For this reason, only multiple AZ Red Hat OpenShift Service on AWS clusters can be used with ALBs.

  • You have access to the OpenShift CLI (oc).
  • You have access to the AWS CLI (aws).

Procedure

  • Configure the following environment variables:

    $ export AWS_PAGER=""
    $ export CLUSTER=$(oc get infrastructure cluster -o=jsonpath="{.status.infrastructureName}")
    $ export REGION=$(oc get infrastructure cluster -o=jsonpath="{.status.platformStatus.aws.region}")
    $ export OIDC_ENDPOINT=$(oc get authentication.config.openshift.io cluster -o jsonpath='{.spec.serviceAccountIssuer}' | sed  's|^https://||')
    $ export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
    $ export SCRATCH="/tmp/${CLUSTER}/alb-waf"
    $ mkdir -p ${SCRATCH}
    $ echo "Cluster: $(echo ${CLUSTER} | sed 's/-[a-z0-9]\{5\}$//'), Region: ${REGION}, OIDC Endpoint: ${OIDC_ENDPOINT}, AWS Account ID: ${AWS_ACCOUNT_ID}"

6.1.1. Tag your AWS VPC and subnets

You need to tag your subnets and Virtual Private Cloud (VPC) before using these resources.

Note

These steps only apply to clusters that were deployed into existing VPCs. If you did not deploy your cluster into an existing VPC, proceed to the installation steps.

Procedure

  1. Set the following variables to the proper values for your Red Hat OpenShift Service on AWS deployment:

    $ export VPC_ID=<vpc-id>
    $ export PUBLIC_SUBNET_IDS=(<space-separated-list-of-ids>)
    $ export PRIVATE_SUBNET_IDS=(<space-separated-list-of-ids>)

    where:

    VPC_ID=<vpc-id>
    Replace with the VPC ID of the cluster, for example: export VPC_ID=vpc-04c429b7dbc4680ba.
    PUBLIC_SUBNET_IDS=(<space-separated-list-of-ids>)
    Replace with a space-separated list of the public subnet IDs of the cluster, making sure to preserve the (). For example: export PUBLIC_SUBNET_IDS=(subnet-056fd6861ad332ba2 subnet-08ce3b4ec753fe74c subnet-071aa28228664972f).
    PRIVATE_SUBNET_IDS=(<space-separated-list-of-ids>)
    Replace with a space-separated list of the private subnet IDs of the cluster, making sure to preserve the (). For example: export PRIVATE_SUBNET_IDS=(subnet-0b933d72a8d72c36a subnet-0817eb72070f1d3c2 subnet-0806e64159b66665a).
  2. Add a tag to your cluster’s VPC with the cluster identifier:

    $ aws ec2 create-tags --resources ${VPC_ID} \
      --tags Key=kubernetes.io/cluster/${CLUSTER},Value=shared --region ${REGION}
  3. Add a tag to your public subnets:

    $ aws ec2 create-tags \
      --resources ${PUBLIC_SUBNET_IDS} \
      --tags Key=kubernetes.io/role/elb,Value='1' \
            Key=kubernetes.io/cluster/${CLUSTER},Value=shared \
      --region ${REGION}
  4. Add a tag to your private subnets:

    $ aws ec2 create-tags \
      --resources ${PRIVATE_SUBNET_IDS} \
      --tags Key=kubernetes.io/role/internal-elb,Value='1' \
            Key=kubernetes.io/cluster/${CLUSTER},Value=shared \
      --region ${REGION}

6.2. Deploy the AWS Load Balancer Operator

The AWS Load Balancer Operator is used to install, manage, and configure an instance of aws-load-balancer-controller in a Red Hat OpenShift Service on AWS cluster. To deploy Application Load Balancers (ALBs) in Red Hat OpenShift Service on AWS, you must first deploy the AWS Load Balancer Operator.

Procedure

  1. Create a new project to deploy the AWS Load Balancer Operator into by running the following command:

    $ oc new-project aws-load-balancer-operator
  2. Create an AWS IAM policy for the AWS Load Balancer Controller if one does not already exist by running the following command:

    Note

    The policy is sourced from Content from raw.githubusercontent.com is not included.the upstream AWS Load Balancer Controller policy. This is required by the Operator to function.

    $ POLICY_ARN=$(aws iam list-policies --query \
         "Policies[?PolicyName=='aws-load-balancer-operator-policy'].{ARN:Arn}" \
         --output text)
    $ if [[ -z "${POLICY_ARN}" ]]; then
        wget -O "${SCRATCH}/load-balancer-operator-policy.json" \
           https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/main/docs/install/iam_policy.json
         POLICY_ARN=$(aws --region "$REGION" --query Policy.Arn \
         --output text iam create-policy \
         --policy-name aws-load-balancer-operator-policy \
         --policy-document "file://${SCRATCH}/load-balancer-operator-policy.json")
    fi
  3. Create an AWS IAM trust policy for AWS Load Balancer Operator:

    $ cat <<EOF > "${SCRATCH}/trust-policy.json"
    {
     "Version": "2012-10-17",
     "Statement": [
     {
     "Effect": "Allow",
     "Condition": {
       "StringEquals" : {
         "${OIDC_ENDPOINT}:sub": ["system:serviceaccount:aws-load-balancer-operator:aws-load-balancer-operator-controller-manager", "system:serviceaccount:aws-load-balancer-operator:aws-load-balancer-controller-cluster"]
       }
     },
     "Principal": {
       "Federated": "arn:aws:iam::$AWS_ACCOUNT_ID:oidc-provider/${OIDC_ENDPOINT}"
     },
     "Action": "sts:AssumeRoleWithWebIdentity"
     }
     ]
    }
    EOF
  4. Create an AWS IAM role for the AWS Load Balancer Operator:

    $ ROLE_ARN=$(aws iam create-role --role-name "${CLUSTER}-alb-operator" \
       --assume-role-policy-document "file://${SCRATCH}/trust-policy.json" \
       --query Role.Arn --output text)
  5. Attach the AWS Load Balancer Operator policy to the IAM role we created previously by running the following command:

    $ aws iam attach-role-policy --role-name "${CLUSTER}-alb-operator" \
         --policy-arn ${POLICY_ARN}
  6. Create a secret for the AWS Load Balancer Operator to assume the newly created AWS IAM role:

    $ cat << EOF | oc apply -f -
    apiVersion: v1
    kind: Secret
    metadata:
      name: aws-load-balancer-operator
      namespace: aws-load-balancer-operator
    stringData:
      credentials: |
        [default]
        role_arn = ${ROLE_ARN}
        web_identity_token_file = /var/run/secrets/openshift/serviceaccount/token
    EOF
  7. Install the AWS Load Balancer Operator:

    $ cat << EOF | oc apply -f -
    apiVersion: operators.coreos.com/v1
    kind: OperatorGroup
    metadata:
      name: aws-load-balancer-operator
      namespace: aws-load-balancer-operator
    spec:
      upgradeStrategy: Default
    ---
    apiVersion: operators.coreos.com/v1alpha1
    kind: Subscription
    metadata:
      name: aws-load-balancer-operator
      namespace: aws-load-balancer-operator
    spec:
      channel: stable-v1.0
      installPlanApproval: Automatic
      name: aws-load-balancer-operator
      source: redhat-operators
      sourceNamespace: openshift-marketplace
      startingCSV: aws-load-balancer-operator.v1.0.0
    EOF
  8. Deploy an instance of the AWS Load Balancer Controller using the Operator:

    $ cat << EOF | oc apply -f -
    apiVersion: networking.olm.openshift.io/v1
    kind: AWSLoadBalancerController
    metadata:
      name: cluster
    spec:
      credentials:
        name: aws-load-balancer-operator
      enabledAddons:
        - AWSWAFv2
    EOF

    If you get an error, the Operator has not completed installing yet. Wait briefly and retry the step.

  9. Check that the Operator and controller pods are both running:

    $ oc -n aws-load-balancer-operator get pods

    Example output

    NAME                                                             READY   STATUS    RESTARTS   AGE
    aws-load-balancer-controller-cluster-6ddf658785-pdp5d            1/1     Running   0          99s
    aws-load-balancer-operator-controller-manager-577d9ffcb9-w6zqn   2/2     Running   0          2m4s

    If the pods aren’t running yet, wait briefly and retry the step.

6.3. Deploy a sample application

Deploy a sample application with an AWS Application Load Balancer (ALB) Ingress to verify your load balancer configuration.

Procedure

  1. Create a new project for the sample application:

    $ oc new-project hello-world
  2. Deploy a hello-world application:

    $ oc new-app -n hello-world --image=docker.io/openshift/hello-openshift
  3. Convert the pre-created service resource to a NodePort service type:

    $ oc -n hello-world patch service hello-openshift -p '{"spec":{"type":"NodePort"}}'
  4. Deploy an AWS ALB using the AWS Load Balancer Operator:

    $ cat << EOF | oc apply -f -
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: hello-openshift-alb
      namespace: hello-world
      annotations:
        alb.ingress.kubernetes.io/scheme: internet-facing
    spec:
      ingressClassName: alb
      rules:
        - http:
            paths:
              - path: /
                pathType: Exact
                backend:
                  service:
                    name: hello-openshift
                    port:
                      number: 8080
    EOF
  5. Curl the AWS ALB Ingress endpoint to verify the hello-world application is accessible:

    Note

    AWS ALB provisioning takes a few minutes. If you receive an error that says curl: (6) Could not resolve host, please wait and try again.

    $ INGRESS=$(oc -n hello-world get ingress hello-openshift-alb -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
    $ curl "http://${INGRESS}"

    Example output

    Hello OpenShift!

6.4. Configure the AWS WAF

You can use the AWS Web Application Firewall (WAF) service to monitor, protect, and control the HTTP and HTTPS requests that are forwarded to your protected web application resources, such as Red Hat OpenShift Service on AWS.

Procedure

  1. Create an AWS WAF rules file to apply to your web access control list (ACL):

    $ cat << EOF > ${SCRATCH}/waf-rules.json
    [
        {
          "Name": "AWS-AWSManagedRulesCommonRuleSet",
          "Priority": 0,
          "Statement": {
            "ManagedRuleGroupStatement": {
              "VendorName": "AWS",
              "Name": "AWSManagedRulesCommonRuleSet"
            }
          },
          "OverrideAction": {
            "None": {}
          },
          "VisibilityConfig": {
            "SampledRequestsEnabled": true,
            "CloudWatchMetricsEnabled": true,
            "MetricName": "AWS-AWSManagedRulesCommonRuleSet"
          }
        },
        {
          "Name": "AWS-AWSManagedRulesSQLiRuleSet",
          "Priority": 1,
          "Statement": {
            "ManagedRuleGroupStatement": {
              "VendorName": "AWS",
              "Name": "AWSManagedRulesSQLiRuleSet"
            }
          },
          "OverrideAction": {
            "None": {}
          },
          "VisibilityConfig": {
            "SampledRequestsEnabled": true,
            "CloudWatchMetricsEnabled": true,
            "MetricName": "AWS-AWSManagedRulesSQLiRuleSet"
          }
        }
    ]
    EOF

    This enables the Core (Common) and SQL AWS Managed Rule Sets.

  2. Create an AWS WAF Web ACL using the rules you specified in the previous steps:

    $ WAF_ARN=$(aws wafv2 create-web-acl \
      --name ${CLUSTER}-waf \
      --region ${REGION} \
      --default-action Allow={} \
      --scope REGIONAL \
      --visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=${CLUSTER}-waf-metrics \
      --rules file://${SCRATCH}/waf-rules.json \
      --query 'Summary.ARN' \
      --output text)
  3. Annotate the Ingress resource with the AWS WAF Web ACL (Amazon Resource Name) ARN:

    $ oc annotate -n hello-world ingress.networking.k8s.io/hello-openshift-alb \
      alb.ingress.kubernetes.io/wafv2-acl-arn=${WAF_ARN}

Verification

  1. Wait 10 seconds for the rules to propagate and test that the application still works:

    $ curl "http://${INGRESS}"

    Example output

    Hello OpenShift!

  2. Test that the WAF denies a bad request:

    $ curl -X POST "http://${INGRESS}" \
      -F "user='<script><alert>Hello></alert></script>'"

    Example output

    <html>
    <head><title>403 Forbidden</title></head>
    <body>
    <center><h1>403 Forbidden</h1></center>
    </body>
    </html

    Note

    Activation of the AWS WAF integration can sometimes take several minutes. If you do not receive a 403 Forbidden error, please wait a few seconds and try again.

    The expected result is a 403 Forbidden error, which means the AWS WAF is protecting your application.

6.5. Additional resources

Chapter 7. Tutorial: Deploy OpenShift API for Data Protection on a Red Hat OpenShift Service on AWS cluster

Deploy OpenShift API for Data Protection on your Red Hat OpenShift Service on AWS cluster to back up and restore application workloads.

Important

This content is authored by Red Hat experts, but has not yet been tested on every supported configuration.

7.1. Set up your environment

You can use environment variables to ensure consistency across the commands within this lab.

Prerequisites

Procedure

  • Prepare the environment variables:

    Note

    Change the cluster name to match your Red Hat OpenShift Service on AWS cluster and ensure you are logged into the cluster as an Administrator. Ensure all fields are output correctly before moving on.

    $ export CLUSTER_NAME=$(oc get infrastructure cluster -o=jsonpath="{.status.infrastructureName}"  | sed 's/-[a-z0-9]\{5\}$//')
    $ export ROSA_CLUSTER_ID=$(rosa describe cluster -c ${CLUSTER_NAME} --output json | jq -r .id)
    $ export REGION=$(rosa describe cluster -c ${CLUSTER_NAME} --output json | jq -r .region.id)
    $ export OIDC_ENDPOINT=$(oc get authentication.config.openshift.io cluster -o jsonpath='{.spec.serviceAccountIssuer}' | sed  's|^https://||')
    $ export AWS_ACCOUNT_ID=`aws sts get-caller-identity --query Account --output text`
    $ export CLUSTER_VERSION=`rosa describe cluster -c ${CLUSTER_NAME} -o json | jq -r .version.raw_id | cut -f -2 -d '.'`
    $ export ROLE_NAME="${CLUSTER_NAME}-openshift-oadp-aws-cloud-credentials"
    $ export AWS_PAGER=""
    $ export SCRATCH="/tmp/${CLUSTER_NAME}/oadp"
    $ mkdir -p ${SCRATCH}
    $ echo "Cluster ID: ${ROSA_CLUSTER_ID}, Region: ${REGION}, OIDC Endpoint: ${OIDC_ENDPOINT}, AWS Account ID: ${AWS_ACCOUNT_ID}"

7.2. Prepare your AWS account

Create the AWS Identity and Access Management (IAM) policy, trust policy, and role to grant OpenShift API for Data Protection access to Amazon S3 and Amazon EC2 resources required for backup and restore operations.

Procedure

  1. Create an IAM policy to enable S3 access:

    $ POLICY_ARN=$(aws iam list-policies --query "Policies[?PolicyName=='RosaOadpVer1'].{ARN:Arn}" --output text)
    if [[ -z "${POLICY_ARN}" ]]; then
    $ cat << EOF > ${SCRATCH}/policy.json
    {
    "Version": "2012-10-17",
    "Statement": [
     {
       "Effect": "Allow",
       "Action": [
         "s3:CreateBucket",
         "s3:DeleteBucket",
         "s3:PutBucketTagging",
         "s3:GetBucketTagging",
         "s3:PutEncryptionConfiguration",
         "s3:GetEncryptionConfiguration",
         "s3:PutLifecycleConfiguration",
         "s3:GetLifecycleConfiguration",
         "s3:GetBucketLocation",
         "s3:ListBucket",
         "s3:GetObject",
         "s3:PutObject",
         "s3:DeleteObject",
         "s3:ListBucketMultipartUploads",
         "s3:AbortMultipartUpload",
         "s3:ListMultipartUploadParts",
         "ec2:DescribeSnapshots",
         "ec2:DescribeVolumes",
         "ec2:DescribeVolumeAttribute",
         "ec2:DescribeVolumesModifications",
         "ec2:DescribeVolumeStatus",
         "ec2:CreateTags",
         "ec2:CreateVolume",
         "ec2:CreateSnapshot",
         "ec2:DeleteSnapshot"
       ],
       "Resource": "*"
     }
    ]}
    EOF
    $ POLICY_ARN=$(aws iam create-policy --policy-name "RosaOadpVer1" \
    --policy-document file:///${SCRATCH}/policy.json --query Policy.Arn \
    --tags Key=rosa_openshift_version,Value=${CLUSTER_VERSION} Key=rosa_role_prefix,Value=ManagedOpenShift Key=operator_namespace,Value=openshift-oadp Key=operator_name,Value=openshift-oadp \
    --output text)
    fi
    $ echo ${POLICY_ARN}
  2. Create an IAM role trust policy for the cluster:

    $ cat <<EOF > ${SCRATCH}/trust-policy.json
    {
      "Version": "2012-10-17",
      "Statement": [{
        "Effect": "Allow",
        "Principal": {
          "Federated": "arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider/${OIDC_ENDPOINT}"
        },
        "Action": "sts:AssumeRoleWithWebIdentity",
        "Condition": {
          "StringEquals": {
             "${OIDC_ENDPOINT}:sub": [
               "system:serviceaccount:openshift-adp:openshift-adp-controller-manager",
               "system:serviceaccount:openshift-adp:velero"]
          }
        }
      }]
    }
    EOF
    $ ROLE_ARN=$(aws iam create-role --role-name \
     "${ROLE_NAME}" \
      --assume-role-policy-document file://${SCRATCH}/trust-policy.json \
      --tags Key=rosa_cluster_id,Value=${ROSA_CLUSTER_ID} Key=rosa_openshift_version,Value=${CLUSTER_VERSION} Key=rosa_role_prefix,Value=ManagedOpenShift Key=operator_namespace,Value=openshift-adp Key=operator_name,Value=openshift-oadp \
      --query Role.Arn --output text)
    
    $ echo ${ROLE_ARN}
  3. Attach the IAM policy to the IAM role:

    $ aws iam attach-role-policy --role-name "${ROLE_NAME}" \
     --policy-arn ${POLICY_ARN}

7.3. Deploy OADP on the cluster

Deploy OpenShift API for Data Protection (OADP) to your cluster using the OpenShift CLI (oc) tool to enable Velero-based backup and restore.

Procedure

  1. Create a namespace for OADP:

    $ oc create namespace openshift-adp
  2. Create a credentials secret:

    $ cat <<EOF > ${SCRATCH}/credentials
    [default]
    role_arn = ${ROLE_ARN}
    web_identity_token_file = /var/run/secrets/openshift/serviceaccount/token
    region=<aws_region>
    EOF
    $ oc -n openshift-adp create secret generic cloud-credentials \
     --from-file=${SCRATCH}/credentials

    where:

    <aws_region>
    Replace with the AWS region to use for the Security Token Service (STS) endpoint.
  3. Deploy the OADP Operator:

    Note

    There is currently an issue with version 1.1 of the Operator with backups that have a PartiallyFailed status. This does not seem to affect the backup and restore process, but it should be noted as there are issues with it.

    $ cat << EOF | oc create -f -
    apiVersion: operators.coreos.com/v1
    kind: OperatorGroup
    metadata:
     generateName: openshift-adp-
     namespace: openshift-adp
     name: oadp
    spec:
     targetNamespaces:
     - openshift-adp
    ---
    apiVersion: operators.coreos.com/v1alpha1
    kind: Subscription
    metadata:
     name: redhat-oadp-operator
     namespace: openshift-adp
    spec:
     channel: stable-1.2
     installPlanApproval: Automatic
     name: redhat-oadp-operator
     source: redhat-operators
     sourceNamespace: openshift-marketplace
    EOF
  4. Wait for the Operator to be ready:

    $ watch oc -n openshift-adp get pods

    Example output

    NAME                                                READY   STATUS    RESTARTS   AGE
    openshift-adp-controller-manager-546684844f-qqjhn   1/1     Running   0          22s

  5. Create Cloud Storage:

    $ cat << EOF | oc create -f -
    apiVersion: oadp.openshift.io/v1alpha1
    kind: CloudStorage
    metadata:
     name: ${CLUSTER_NAME}-oadp
     namespace: openshift-adp
    spec:
     creationSecret:
       key: credentials
       name: cloud-credentials
     enableSharedConfig: true
     name: ${CLUSTER_NAME}-oadp
     provider: aws
     region: $REGION
    EOF
  6. Check your application’s storage default storage class by running the following command with your desired namespace:

    $ oc get pvc -n <namespace>

    Example output

    NAME     STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    applog   Bound    pvc-351791ae-b6ab-4e8b-88a4-30f73caf5ef8   1Gi        RWO            gp3-csi        4d19h
    mysql    Bound    pvc-16b8e009-a20a-4379-accc-bc81fedd0621   1Gi        RWO            gp3-csi        4d19h

    $ oc get storageclass

    Example output

    NAME                PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
    gp2                 kubernetes.io/aws-ebs   Delete          WaitForFirstConsumer   true                   4d21h
    gp2-csi             ebs.csi.aws.com         Delete          WaitForFirstConsumer   true                   4d21h
    gp3                 ebs.csi.aws.com         Delete          WaitForFirstConsumer   true                   4d21h
    gp3-csi (default)   ebs.csi.aws.com         Delete          WaitForFirstConsumer   true                   4d21h

    Using either gp3-csi, gp2-csi, gp3 or gp2 will work. If the application(s) that are being backed up are all using Persistent Volumes (PVs) with the Container Storage Interface (CSI), include the CSI plugin in the OADP Data Protection Application (DPA) configuration.

  7. CSI only: Deploy a Data Protection Application:

    $ cat << EOF | oc create -f -
    apiVersion: oadp.openshift.io/v1alpha1
    kind: DataProtectionApplication
    metadata:
     name: ${CLUSTER_NAME}-dpa
     namespace: openshift-adp
    spec:
     backupImages: true
     features:
       dataMover:
         enable: false
     backupLocations:
     - bucket:
         cloudStorageRef:
           name: ${CLUSTER_NAME}-oadp
         credential:
           key: credentials
           name: cloud-credentials
         prefix: velero
         default: true
         config:
           region: ${REGION}
     configuration:
       velero:
         defaultPlugins:
         - openshift
         - aws
         - csi
       restic:
         enable: false
    EOF
    Note

    If you run this command for CSI volumes, you can skip the next step.

  8. Non-CSI volumes: Deploy a Data Protection Application:

    $ cat << EOF | oc create -f -
    apiVersion: oadp.openshift.io/v1alpha1
    kind: DataProtectionApplication
    metadata:
     name: ${CLUSTER_NAME}-dpa
     namespace: openshift-adp
    spec:
     backupImages: true
     features:
       dataMover:
         enable: false
     backupLocations:
     - bucket:
         cloudStorageRef:
           name: ${CLUSTER_NAME}-oadp
         credential:
           key: credentials
           name: cloud-credentials
         prefix: velero
         default: true
         config:
           region: ${REGION}
     configuration:
       velero:
         defaultPlugins:
         - openshift
         - aws
       restic:
         enable: false
     snapshotLocations:
       - velero:
           config:
             credentialsFile: /tmp/credentials/openshift-adp/cloud-credentials-credentials
             enableSharedConfig: 'true'
             profile: default
             region: ${REGION}
           provider: aws
    EOF
    Note
    • In OADP 1.1.x Red Hat OpenShift Service on AWS STS environments, the container image backup and restore (spec.backupImages) value must be set to false as it is not supported.
    • The Restic feature (restic.enable=false) is disabled and not supported in Red Hat OpenShift Service on AWS STS environments.
    • The DataMover feature (dataMover.enable=false) is disabled and not supported in Red Hat OpenShift Service on AWS STS environments.

7.4. Back up and restore a workload

Back up and restore a workload to verify that OpenShift API for Data Protection is working correctly on your cluster.

Note

The following sample hello-world application has no attached persistent volumes. Either Data Protection Application (DPA) configuration will work.

Procedure

  1. Create a workload to back up:

    1. Create a namespace by running:

      $ oc create namespace hello-world
    2. Create an application by running:

      $ oc new-app -n hello-world --image=docker.io/openshift/hello-openshift
  2. Expose the route:

    $ oc expose service/hello-openshift -n hello-world
  3. Check that the application is working:

    $ curl `oc get route/hello-openshift -n hello-world -o jsonpath='{.spec.host}'`

    Example output

    Hello OpenShift!

  4. Back up the workload:

    $ cat << EOF | oc create -f -
    apiVersion: velero.io/v1
    kind: Backup
    metadata:
     name: hello-world
     namespace: openshift-adp
    spec:
     includedNamespaces:
     - hello-world
     storageLocation: ${CLUSTER_NAME}-dpa-1
     ttl: 720h0m0s
    EOF
  5. Wait until the backup is done:

    $ watch "oc -n openshift-adp get backup hello-world -o json | jq .status"

    Example output

    {
     "completionTimestamp": "2022-09-07T22:20:44Z",
     "expiration": "2022-10-07T22:20:22Z",
     "formatVersion": "1.1.0",
     "phase": "Completed",
     "progress": {
       "itemsBackedUp": 58,
       "totalItems": 58
     },
     "startTimestamp": "2022-09-07T22:20:22Z",
     "version": 1
    }

  6. Delete the demo workload:

    $ oc delete ns hello-world
  7. Restore from the backup:

    $ cat << EOF | oc create -f -
    apiVersion: velero.io/v1
    kind: Restore
    metadata:
     name: hello-world
     namespace: openshift-adp
    spec:
     backupName: hello-world
    EOF
  8. Wait for the restore to finish:

    $ watch "oc -n openshift-adp get restore hello-world -o json | jq .status"

    Example output

    {
     "completionTimestamp": "2022-09-07T22:25:47Z",
     "phase": "Completed",
     "progress": {
       "itemsRestored": 38,
       "totalItems": 38
     },
     "startTimestamp": "2022-09-07T22:25:28Z",
     "warnings": 9
    }

  9. Check that the workload is restored:

    $ oc -n hello-world get pods

    Example output

    NAME                              READY   STATUS    RESTARTS   AGE
    hello-openshift-9f885f7c6-kdjpj   1/1     Running   0          90s

    $ curl `oc get route/hello-openshift -n hello-world -o jsonpath='{.spec.host}'`

    Example output

    Hello OpenShift!

7.5. Clean up AWS resources

Clean up your AWS resources after completing this lab tutorial.

Procedure

  1. Delete the workload:

    $ oc delete ns hello-world
  2. Remove the backup and restore resources from the cluster if they are no longer required:

    $ oc delete backups.velero.io hello-world
    $ oc delete restores.velero.io hello-world
  3. Delete the backup, restore, and remote objects in S3:

    $ velero backup delete hello-world
    $ velero restore delete hello-world
  4. Delete the Data Protection Application:

    $ oc -n openshift-adp delete dpa ${CLUSTER_NAME}-dpa
  5. Delete the Cloud Storage:

    $ oc -n openshift-adp delete cloudstorage ${CLUSTER_NAME}-oadp
    Warning

    If this command hangs, you might need to delete the finalizer:

    $ oc -n openshift-adp patch cloudstorage ${CLUSTER_NAME}-oadp -p '{"metadata":{"finalizers":null}}' --type=merge
  6. Remove the Operator if it is no longer required:

    $ oc -n openshift-adp delete subscription oadp-operator
  7. Remove the namespace for the Operator:

    $ oc delete ns redhat-openshift-adp
  8. Remove the Custom Resource Definitions from the cluster if you no longer wish to have them:

    $ for CRD in `oc get crds | grep velero | awk '{print $1}'`; do oc delete crd $CRD; done
    $ for CRD in `oc get crds | grep -i oadp | awk '{print $1}'`; do oc delete crd $CRD; done
  9. Delete the AWS S3 Bucket:

    $ aws s3 rm s3://${CLUSTER_NAME}-oadp --recursive
    $ aws s3api delete-bucket --bucket ${CLUSTER_NAME}-oadp
  10. Detach the policy from the role:

    $ aws iam detach-role-policy --role-name "${ROLE_NAME}" \
     --policy-arn "${POLICY_ARN}"
  11. Delete the role:

    $ aws iam delete-role --role-name "${ROLE_NAME}"

7.6. Additional resources

Chapter 8. Tutorial: AWS Load Balancer Operator on Red Hat OpenShift Service on AWS

Install and configure the AWS Load Balancer Operator to provision advanced AWS Application Load Balancers (ALBs) and Network Load Balancers (NLBs) for your Red Hat OpenShift Service on AWS cluster.

Important

This content is authored by Red Hat experts, but has not yet been tested on every supported configuration.

8.1. AWS Load Balancer Operator overview

The AWS Load Balancer Operator installs and manages the AWS Load Balancer Controller, which provisions Application Load Balancers (ALBs) and Network Load Balancers (NLBs) with advanced annotations beyond the default in-tree provider.

Tip

Load Balancers created by the AWS Load Balancer Operator cannot be used for OpenShift Routes, and should only be used for individual services or ingress resources that do not need the full layer 7 capabilities of an OpenShift Route.

Compared with the default AWS in-tree load balancer provider, the AWS Load Balancer Controller is developed with advanced annotations for both ALBs and NLBs. Some advanced use cases are:

  • Using native Kubernetes Ingress objects with ALBs.
  • Integrating ALBs with the AWS Web Application Firewall (WAF) service. WAFv1, WAF classic, is no longer supported; use WAFv2.
  • Specifying custom NLB source IP ranges.
  • Specifying custom NLB internal IP addresses.

The AWS Load Balancer Operator is used to install, manage, and configure an instance of aws-load-balancer-controller in a Red Hat OpenShift Service on AWS cluster. For more information, see Additional resources.

8.2. Set up your environment

Set environment variables for your cluster name, region, and OpenID Connect (OIDC) endpoint to ensure consistency across AWS Load Balancer Operator commands.

Prerequisites

  • You have created a multi-availability zone (AZ) Red Hat OpenShift Service on AWS cluster.

    Note

    AWS Application Load Balancers (ALBs) require a multi-AZ cluster and three public subnets split across three AZs in the same Virtual Private Cloud (VPC) as the cluster. This makes ALBs unsuitable for many PrivateLink clusters. AWS Network Load Balancers (NLBs) do not have this restriction.

  • You have created a Bring Your Own (BYO) VPC cluster.
  • You have access to the AWS CLI (aws).
  • You have access to the OpenShift CLI (oc).

Procedure

  • Prepare the environment variables:

    $ export AWS_PAGER=""
    $ export ROSA_CLUSTER_NAME=$(oc get infrastructure cluster -o=jsonpath="{.status.infrastructureName}"  | sed 's/-[a-z0-9]\{5\}$//')
    $ export REGION=$(oc get infrastructure cluster -o=jsonpath="{.status.platformStatus.aws.region}")
    $ export OIDC_ENDPOINT=$(oc get authentication.config.openshift.io cluster -o jsonpath='{.spec.serviceAccountIssuer}' | sed  's|^https://||')
    $ export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
    $ export SCRATCH="/tmp/${ROSA_CLUSTER_NAME}/alb-operator"
    $ mkdir -p ${SCRATCH}
    $ echo "Cluster: ${ROSA_CLUSTER_NAME}, Region: ${REGION}, OIDC Endpoint: ${OIDC_ENDPOINT}, AWS Account ID: ${AWS_ACCOUNT_ID}"

8.2.1. Tag your AWS VPC and subnets

Tag your Virtual Private Cloud (VPC) and subnets so the AWS Load Balancer Operator can identify your network resources and assign load balancers to the correct public or private subnets.

Note

This section only applies to clusters that were deployed into existing VPCs. If you did not deploy your cluster into an existing VPC, skip this section and proceed to the installation section below.

Procedure

  1. Set the below variables to the proper values for your cluster deployment:

    $ export VPC_ID=<vpc-id>
    $ export PUBLIC_SUBNET_IDS=<public-subnets>
    $ export PRIVATE_SUBNET_IDS=<private-subnets>
    $ export CLUSTER_NAME=$(oc get infrastructure cluster -o=jsonpath="{.status.infrastructureName}")
  2. Add a tag to your cluster’s VPC with the cluster name:

    $ aws ec2 create-tags --resources ${VPC_ID} --tags Key=kubernetes.io/cluster/${CLUSTER_NAME},Value=owned --region ${REGION}
  3. Add a tag to your public subnets:

    $ aws ec2 create-tags \
         --resources ${PUBLIC_SUBNET_IDS} \
         --tags Key=kubernetes.io/role/elb,Value='' \
         --region ${REGION}
  4. Add a tag to your private subnets:

    $ aws ec2 create-tags \
         --resources "${PRIVATE_SUBNET_IDS}" \
         --tags Key=kubernetes.io/role/internal-elb,Value='' \
         --region ${REGION}

8.3. Install the AWS Load Balancer Operator

Install the AWS Load Balancer Operator to provision and manage AWS Application Load Balancers (ALBs) and Network Load Balancers (NLBs) for your Red Hat OpenShift Service on AWS cluster.

Procedure

  1. Create an AWS Identity and Access Management (IAM) policy for the AWS Load Balancer Controller:

    Note

    The policy is sourced from Content from raw.githubusercontent.com is not included.the upstream AWS Load Balancer Controller policy plus permission to create tags on subnets. This is required by the Operator to function.

    $ oc new-project aws-load-balancer-operator
    $ POLICY_ARN=$(aws iam list-policies --query \
         "Policies[?PolicyName=='aws-load-balancer-operator-policy'].{ARN:Arn}" \
         --output text)
    $ if [[ -z "${POLICY_ARN}" ]]; then
        wget -O "${SCRATCH}/load-balancer-operator-policy.json" \
           https://raw.githubusercontent.com/rh-mobb/documentation/main/content/rosa/aws-load-balancer-operator/load-balancer-operator-policy.json
         POLICY_ARN=$(aws --region "$REGION" --query Policy.Arn \
         --output text iam create-policy \
         --policy-name aws-load-balancer-operator-policy \
         --policy-document "file://${SCRATCH}/load-balancer-operator-policy.json")
    fi
    $ echo $POLICY_ARN
  2. Create an AWS IAM trust policy for AWS Load Balancer Operator:

    $ cat <<EOF > "${SCRATCH}/trust-policy.json"
    {
     "Version": "2012-10-17",
     "Statement": [
     {
     "Effect": "Allow",
     "Condition": {
       "StringEquals" : {
         "${OIDC_ENDPOINT}:sub": ["system:serviceaccount:aws-load-balancer-operator:aws-load-balancer-operator-controller-manager", "system:serviceaccount:aws-load-balancer-operator:aws-load-balancer-controller-cluster"]
       }
     },
     "Principal": {
       "Federated": "arn:aws:iam::$AWS_ACCOUNT_ID:oidc-provider/${OIDC_ENDPOINT}"
     },
     "Action": "sts:AssumeRoleWithWebIdentity"
     }
     ]
    }
    EOF
  3. Create an AWS IAM role for the AWS Load Balancer Operator:

    $ ROLE_ARN=$(aws iam create-role --role-name "${ROSA_CLUSTER_NAME}-alb-operator" \
       --assume-role-policy-document "file://${SCRATCH}/trust-policy.json" \
       --query Role.Arn --output text)
    $ echo $ROLE_ARN
    
    $ aws iam attach-role-policy --role-name "${ROSA_CLUSTER_NAME}-alb-operator" \
         --policy-arn $POLICY_ARN
  4. Create a secret for the AWS Load Balancer Operator to assume the newly created AWS IAM role:

    $ cat << EOF | oc apply -f -
    apiVersion: v1
    kind: Secret
    metadata:
      name: aws-load-balancer-operator
      namespace: aws-load-balancer-operator
    stringData:
      credentials: |
        [default]
        role_arn = $ROLE_ARN
        web_identity_token_file = /var/run/secrets/openshift/serviceaccount/token
    EOF
  5. Install the AWS Load Balancer Operator:

    $ cat << EOF | oc apply -f -
    apiVersion: operators.coreos.com/v1
    kind: OperatorGroup
    metadata:
      name: aws-load-balancer-operator
      namespace: aws-load-balancer-operator
    spec:
      upgradeStrategy: Default
    ---
    apiVersion: operators.coreos.com/v1alpha1
    kind: Subscription
    metadata:
      name: aws-load-balancer-operator
      namespace: aws-load-balancer-operator
    spec:
      channel: stable-v1.0
      installPlanApproval: Automatic
      name: aws-load-balancer-operator
      source: redhat-operators
      sourceNamespace: openshift-marketplace
      startingCSV: aws-load-balancer-operator.v1.0.0
    EOF
  6. Deploy an instance of the AWS Load Balancer Controller using the Operator:

    Note

    If you get an error, the Operator has not completed installing yet. Wait briefly and retry the step.

    $ cat << EOF | oc apply -f -
    apiVersion: networking.olm.openshift.io/v1
    kind: AWSLoadBalancerController
    metadata:
      name: cluster
    spec:
      credentials:
        name: aws-load-balancer-operator
    EOF
  7. Check that the Operator and controller pods are both running:

    $ oc -n aws-load-balancer-operator get pods

    Example output

    NAME                                                             READY   STATUS    RESTARTS   AGE
    aws-load-balancer-controller-cluster-6ddf658785-pdp5d            1/1     Running   0          99s
    aws-load-balancer-operator-controller-manager-577d9ffcb9-w6zqn   2/2     Running   0          2m4s

8.4. Validate the AWS Load Balancer Operator deployment

Deploy a sample application with Application Load Balancer (ALB) and Network Load Balancer (NLB) resources to verify that the AWS Load Balancer Operator successfully provisions load balancers to your cluster.

Procedure

  1. Create a new project:

    $ oc new-project hello-world
  2. Deploy a hello-world application:

    $ oc new-app -n hello-world --image=docker.io/openshift/hello-openshift
  3. Configure a NodePort service for the AWS Application Load Balancer (ALB) to connect to:

    $ cat << EOF | oc apply -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: hello-openshift-nodeport
      namespace: hello-world
    spec:
      ports:
        - port: 80
          targetPort: 8080
          protocol: TCP
      type: NodePort
      selector:
        deployment: hello-openshift
    EOF
  4. Deploy an AWS ALB using the AWS Load Balancer Operator:

    $ cat << EOF | oc apply -f -
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: hello-openshift-alb
      namespace: hello-world
      annotations:
        alb.ingress.kubernetes.io/scheme: internet-facing
    spec:
      ingressClassName: alb
      rules:
        - http:
            paths:
              - path: /
                pathType: Exact
                backend:
                  service:
                    name: hello-openshift-nodeport
                    port:
                      number: 80
    EOF
  5. Curl the AWS ALB Ingress endpoint to verify the hello-world application is accessible:

    Note

    AWS ALB provisioning takes a few minutes. If you receive an error that says curl: (6) Could not resolve host, wait and try again.

    $ INGRESS=$(oc -n hello-world get ingress hello-openshift-alb \
        -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
    $ curl "http://${INGRESS}"

    Example output

    Hello OpenShift!

  6. Deploy an AWS Network Load Balancer (NLB) for your hello-world application:

    $ cat << EOF | oc apply -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: hello-openshift-nlb
      namespace: hello-world
      annotations:
        service.beta.kubernetes.io/aws-load-balancer-type: external
        service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: instance
        service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
    spec:
      ports:
        - port: 80
          targetPort: 8080
          protocol: TCP
      type: LoadBalancer
      selector:
        deployment: hello-openshift
    EOF
  7. Test the AWS NLB endpoint:

    Note

    NLB provisioning takes a few minutes. If you receive an error that says curl: (6) Could not resolve host, wait and try again.

    $ NLB=$(oc -n hello-world get service hello-openshift-nlb \
      -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
    $ curl "http://${NLB}"

    Example output

    Hello OpenShift!

8.5. Clean up AWS resources

Remove the sample application, AWS Load Balancer Operator, and associated Identity and Access Management (IAM) roles and policies created during this tutorial.

Procedure

  1. Delete the hello-world application namespace and all the resources in the namespace:

    $ oc delete project hello-world
  2. Delete the AWS Load Balancer Operator and the AWS IAM roles:

    $ oc delete subscription aws-load-balancer-operator -n aws-load-balancer-operator
    $ aws iam detach-role-policy \
      --role-name "${ROSA_CLUSTER_NAME}-alb-operator" \
      --policy-arn $POLICY_ARN
    $ aws iam delete-role \
      --role-name "${ROSA_CLUSTER_NAME}-alb-operator"
  3. Delete the AWS IAM policy:

    $ aws iam delete-policy --policy-arn $POLICY_ARN

8.6. Additional resources

Chapter 9. Tutorial: Configure Microsoft Entra ID as an identity provider

Configure Microsoft Entra ID (formerly Azure Active Directory) as the cluster identity provider to enable user authentication and group-based access control for your Red Hat OpenShift Service on AWS cluster by using OpenID Connect (OIDC).

This tutorial guides you to complete the following tasks:

  1. Register a new application in Entra ID for authentication.
  2. Configure the application registration in Entra ID to include optional and group claims in tokens.
  3. Configure the Red Hat OpenShift Service on AWS cluster to use Entra ID as the identity provider.
  4. Grant additional permissions to individual groups.

9.1. Register a new application in Entra ID for authentication

Register an application in Entra ID using your cluster OAuth callback URL to generate the credentials for cluster authentication.

Prerequisites

Procedure

  1. Create the cluster’s OAuth callback URL by changing the specified variables and running the following command:

    $ domain=$(rosa describe cluster -c <cluster_name> | grep "DNS" | grep -oE '\S+.openshiftapps.com')
    echo "OAuth callback URL: https://oauth.${domain}/oauth2callback/AAD"

    The AAD directory at the end of the OAuth callback URL must match the OAuth identity provider name that you will set up later in this process.

    Note

    Remember to save this callback URL; it will be required later in the process.

  2. Create the Entra ID application by logging in to the Azure portal, and select the Content from portal.azure.com is not included.App registrations blade. Then, select New registration to create a new application.

    Azure Portal - App registrations blade

  3. Name the application, for example openshift-auth.
  4. Select Web from the Redirect URI dropdown and enter the value of the OAuth callback URL you retrieved in the previous step.
  5. After providing the required information, click Register to create the application.

    Azure Portal - Register an application page

  6. Select the Certificates & secrets sub-blade and select New client secret.

    Azure Portal - Certificates and secrets page

  7. Complete the requested details and store the generated client secret value. This secret is required later in this process.

    Important

    After initial setup, you cannot see the client secret. If you did not record the client secret, you must generate a new one.

    Azure Portal - Add a Client Secret page

  8. Select the Overview sub-blade and note the Application (client) ID and Directory (tenant) ID. You will need these values in a future step.

    Azure Portal - Copy Client Secret page

9.2. Optional and group claims for Entra ID application registration

The email and preferred_username Entra ID optional claims provide Red Hat OpenShift Service on AWS with the information it needs to create user accounts. Group claims enable group-based access control.

In addition to individual user authentication, Red Hat OpenShift Service on AWS provides group claim functionality. This functionality allows an OpenID Connect (OIDC) identity provider, such as Entra ID, to offer a user’s group membership for use within Red Hat OpenShift Service on AWS.

9.2.1. Configure optional claims in Entra ID

Configure the email and preferred_username optional claims in Entra ID so that Red Hat OpenShift Service on AWS can identify users during authentication.

Procedure

  1. Click the Token configuration sub-blade and click Add optional claim.

    Azure Portal - Add Optional Claims Page

  2. Select the ID radio button.

    Azure Portal - Add Optional Claims - Token Type

  3. Select the email claim checkbox.

    Azure Portal - Add Optional Claims - email

  4. Select the preferred_username claim checkbox. Then, click Add to configure the email and preferred_username claims your Entra ID application.

    Azure Portal - Add Optional Claims - preferred_username

  5. Follow the prompt in the dialog box to enable the necessary Microsoft Graph permissions.

    Azure Portal - Add Optional Claims - Graph Permissions Prompt

9.2.2. Configure group claims

Configure group claims in Entra ID to allow Red Hat OpenShift Service on AWS to manage user group memberships and enable group-based role bindings in the cluster.

Note

Configuring group claims is an optional step.

Procedure

  1. From the Token configuration sub-blade, click Add groups claim.

    Azure Portal - Add Groups Claim Page

  2. To configure group claims for your Entra ID application, select Security groups and then click Add.

    Note

    In this example, the group claim includes all of the security groups that a user is a member of. In a real production environment, ensure that the group claim only includes groups that apply to Red Hat OpenShift Service on AWS.

    Azure Portal - Edit Groups Claim Page

9.3. Configure Entra ID as the cluster identity provider

Use the ROSA command-line interface (CLI) (rosa) to configure the cluster’s OAuth provider to use Entra ID as its identity provider, enabling users to log in with their Microsoft credentials and optional group-based access control.

Procedure

  1. Create the variables necessary for the identity provider configuration by running the following command:

    $ CLUSTER_NAME=example-cluster
    $ IDP_NAME=AAD
    $ APP_ID=yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy
    $ CLIENT_SECRET=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    $ TENANT_ID=zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz

    where:

    example-cluster
    Replace this with the name of your cluster.
    AAD
    Replace this value with the name you used in the OAuth callback URL that you generated earlier in this process.
    yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy
    Replace this with the Application (client) ID.
    xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    Replace this with the Client Secret.
    zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz
    Replace this with the Directory (tenant) ID.
  2. Configure the cluster’s OAuth provider by running the following command. If you enabled group claims, ensure that you use the --group-claims groups argument.

    • If you enabled group claims, run the following command:

      $ rosa create idp \
      --cluster ${CLUSTER_NAME} \
      --type openid \
      --name ${IDP_NAME} \
      --client-id ${APP_ID} \
      --client-secret ${CLIENT_SECRET} \
      --issuer-url https://login.microsoftonline.com/${TENANT_ID}/v2.0 \
      --email-claims email \
      --name-claims name \
      --username-claims preferred_username \
      --extra-scopes email,profile \
      --groups-claims groups
    • If you did not enable group claims, run the following command:

      $ rosa create idp \
      --cluster ${CLUSTER_NAME} \
      --type openid \
      --name ${IDP_NAME} \
      --client-id ${APP_ID} \
      --client-secret ${CLIENT_SECRET} \
      --issuer-url https://login.microsoftonline.com/${TENANT_ID}/v2.0 \
      --email-claims email \
      --name-claims name \
      --username-claims preferred_username \
      --extra-scopes email,profile

      After a few minutes, the cluster authentication Operator reconciles your changes, and you can log in to the cluster by using Entra ID.

9.4. Additional permissions for individual users and groups

When you first log in, you might notice that you have very limited permissions. By default, Red Hat OpenShift Service on AWS only grants you the ability to create new projects, or namespaces, in the cluster. Other projects are restricted from view.

You must grant these additional abilities to individual users and groups.

9.5. Grant additional permissions to individual users

Grant the cluster-admin role to individual Entra ID users so that they have full access and control over the cluster.

Procedure

  • Grant a user access to the cluster-admin role by running the following command:

    $ rosa grant user cluster-admin --user=<USERNAME> --cluster=${CLUSTER_NAME}

    where:

    <USERNAME>
    Provide the Entra ID username that you want to have cluster admin permissions.

9.6. Grant additional permissions to individual groups

When group claims are enabled, the cluster OAuth provider automatically creates or updates group memberships by using the group ID, but does not create RoleBindings or ClusterRoleBindings. You must create those bindings to grant group-based permissions.

To grant an automatically generated group access to the cluster-admin role, you must create a ClusterRoleBinding to the group ID.

Procedure

  • Create the ClusterRoleBinding by running the following command:

    $ oc create clusterrolebinding cluster-admin-group --clusterrole=cluster-admin --group=<GROUP_ID>

    where:

    <GROUP_ID>
    Specifies the Entra ID group ID that you want to have cluster admin permissions.

    Now, any user in the specified group automatically receives cluster-admin access.

9.7. Additional resources

Chapter 10. Tutorial: Use AWS Secrets Manager CSI on Red Hat OpenShift Service on AWS with STS

The AWS Secrets and Configuration Provider (ASCP) provides a way to expose AWS Secrets as Kubernetes storage volumes. With the ASCP, you can store and manage your secrets in Secrets Manager and then securely retrieve them through your Red Hat OpenShift Service on AWS workloads without hardcoding sensitive data in application configurations.

10.1. Prepare your environment for AWS Secrets Manager

Before creating your application, you need to gain access to your Red Hat OpenShift Service on AWS cluster and configure it with permissions and variables required by the AWS Secrets and Configuration Provider.

Prerequisites

  • You have created a Red Hat OpenShift Service on AWS cluster deployed with Security Token Service (STS).
  • You have installed Helm 3.
  • You have access to the AWS CLI (aws).
  • You have access to the OpenShift CLI (oc).
  • You have access to the jq CLI.

Procedure

  1. Log in to your Red Hat OpenShift Service on AWS cluster by running the following command:

    $ oc login --token=<your-token> --server=<your-server-url>

    You can find your login token by accessing your cluster in This content is not included.pull secret from Red Hat OpenShift Cluster Manager.

  2. Validate that your cluster has STS by running the following command:

    $ oc get authentication.config.openshift.io cluster -o json \
      | jq .spec.serviceAccountIssuer

    Example output

    "https://xxxxx.cloudfront.net/xxxxx"

    If your output is different, do not proceed. See Red Hat documentation on creating an STS cluster before continuing this process.

  3. Set the SecurityContextConstraints permission to allow the Container Storage Interface (CSI) driver to run by running the following command:

    $ oc new-project csi-secrets-store
    $ oc adm policy add-scc-to-user privileged \
        system:serviceaccount:csi-secrets-store:secrets-store-csi-driver
    $ oc adm policy add-scc-to-user privileged \
        system:serviceaccount:csi-secrets-store:csi-secrets-store-provider-aws
  4. Create environment variables to use later in this process by running the following command:

    $ export REGION=$(oc get infrastructure cluster -o=jsonpath="{.status.platformStatus.aws.region}")
    $ export OIDC_ENDPOINT=$(oc get authentication.config.openshift.io cluster \
       -o jsonpath='{.spec.serviceAccountIssuer}' | sed  's|^https://||')
    $ export AWS_ACCOUNT_ID=`aws sts get-caller-identity --query Account --output text`
    $ export AWS_PAGER=""

10.2. Deploy the AWS Secrets and Configuration Provider

Deploy the Secrets Store Container Storage Interface (CSI) Driver and the AWS Secrets and Configuration Provider by using Helm to enable your Red Hat OpenShift Service on AWS workloads to mount AWS Secrets as volumes.

Procedure

  1. Use Helm to register the Secrets Store CSI Driver by running the following command:

    $ helm repo add secrets-store-csi-driver \
        https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts
  2. Update your Helm repositories by running the following command:

    $ helm repo update
  3. Install the Secrets Store CSI Driver by running the following command:

    $ helm upgrade --install -n csi-secrets-store \
        csi-secrets-store-driver secrets-store-csi-driver/secrets-store-csi-driver
  4. Deploy the AWS provider by running the following command:

    $ oc -n csi-secrets-store apply -f \
        https://raw.githubusercontent.com/rh-mobb/documentation/main/content/misc/secrets-store-csi/aws-provider-installer.yaml
  5. Check that both Daemonsets are running by running the following command:

    $ oc -n csi-secrets-store get ds \
        csi-secrets-store-provider-aws \
        csi-secrets-store-driver-secrets-store-csi-driver
  6. Label the Secrets Store CSI Driver to allow use with the restricted pod security profile by running the following command:

    $ oc label csidriver.storage.k8s.io/secrets-store.csi.k8s.io security.openshift.io/csi-ephemeral-volume-profile=restricted

10.3. Create a secret and IAM access policies

Create a secret in AWS Secrets Manager and configure the necessary AWS Identity and Access Management (IAM) policies and roles to allow your application workloads to retrieve the secret securely using the Security Token Service (STS).

Procedure

  1. Create a secret in AWS Secrets Manager by running the following command:

    $ SECRET_ARN=$(aws --region "$REGION" secretsmanager create-secret \
        --name MySecret --secret-string \
        '{"username":"shadowman", "password":"hunter2"}' \
        --query ARN --output text); echo $SECRET_ARN
  2. Create an IAM Access Policy document by running the following command:

    $ cat << EOF > policy.json
    {
       "Version": "2012-10-17",
       "Statement": [{
          "Effect": "Allow",
          "Action": [
            "secretsmanager:GetSecretValue",
            "secretsmanager:DescribeSecret"
          ],
          "Resource": ["$SECRET_ARN"]
          }]
    }
    EOF
  3. Create an IAM Access Policy by running the following command:

    $ POLICY_ARN=$(aws --region "$REGION" --query Policy.Arn \
    --output text iam create-policy \
    --policy-name openshift-access-to-mysecret-policy \
    --policy-document file://policy.json); echo $POLICY_ARN
  4. Create an IAM Role trust policy document by running the following command:

    Note

    The trust policy is locked down to the default service account of a namespace you create later in this process.

    $ cat <<EOF > trust-policy.json
    {
       "Version": "2012-10-17",
       "Statement": [
       {
       "Effect": "Allow",
       "Condition": {
         "StringEquals" : {
           "${OIDC_ENDPOINT}:sub": ["system:serviceaccount:my-application:default"]
          }
        },
        "Principal": {
           "Federated": "arn:aws:iam::$AWS_ACCOUNT_ID:oidc-provider/${OIDC_ENDPOINT}"
        },
        "Action": "sts:AssumeRoleWithWebIdentity"
        }
        ]
    }
    EOF
  5. Create an IAM role by running the following command:

    $ ROLE_ARN=$(aws iam create-role --role-name openshift-access-to-mysecret \
    --assume-role-policy-document file://trust-policy.json \
    --query Role.Arn --output text); echo $ROLE_ARN
  6. Attach the role to the policy by running the following command:

    $ aws iam attach-role-policy --role-name openshift-access-to-mysecret \
        --policy-arn $POLICY_ARN

10.4. Create an application that uses an AWS Secrets Manager secret

Deploy a sample application with the SecretProviderClass Container Storage Interface (CSI) volume to verify that your workload can retrieve secrets from AWS Secrets Manager.

Procedure

  1. Create an OpenShift project by running the following command:

    $ oc new-project my-application
  2. Annotate the default service account to use the Security Token Service (STS) role by running the following command:

    $ oc annotate -n my-application serviceaccount default \
        eks.amazonaws.com/role-arn=$ROLE_ARN
  3. Create a secret provider class to access our secret by running the following command:

    $ cat << EOF | oc apply -f -
    apiVersion: secrets-store.csi.x-k8s.io/v1
    kind: SecretProviderClass
    metadata:
      name: my-application-aws-secrets
    spec:
      provider: aws
      parameters:
        objects: |
          - objectName: "MySecret"
            objectType: "secretsmanager"
    EOF
  4. Create a deployment by using our secret in the following command:

    $ cat << EOF | oc apply -f -
    apiVersion: v1
    kind: Pod
    metadata:
      name: my-application
      labels:
        app: my-application
    spec:
      volumes:
      - name: secrets-store-inline
        csi:
          driver: secrets-store.csi.k8s.io
          readOnly: true
          volumeAttributes:
            secretProviderClass: "my-application-aws-secrets"
      containers:
      - name: my-application-deployment
        image: k8s.gcr.io/e2e-test-images/busybox:1.29
        command:
          - "/bin/sleep"
          - "10000"
        volumeMounts:
        - name: secrets-store-inline
          mountPath: "/mnt/secrets-store"
          readOnly: true
    EOF

Verification

  • Verify the pod has the secret mounted by running the following command:

    $ oc exec -it my-application -- cat /mnt/secrets-store/MySecret

10.5. Clean up AWS resources

Clean up your AWS resources after completing this lab tutorial.

Procedure

  1. Delete the application by running the following command:

    $ oc delete project my-application
  2. Delete the secrets store Container Storage Interface (CSI) driver by running the following command:

    $ helm delete -n csi-secrets-store csi-secrets-store-driver
  3. Delete the security context constraints by running the following command:

    $ oc adm policy remove-scc-from-user privileged \
        system:serviceaccount:csi-secrets-store:secrets-store-csi-driver; oc adm policy remove-scc-from-user privileged \
        system:serviceaccount:csi-secrets-store:csi-secrets-store-provider-aws
  4. Delete the AWS provider by running the following command:

    $ oc -n csi-secrets-store delete -f \
    https://raw.githubusercontent.com/rh-mobb/documentation/main/content/misc/secrets-store-csi/aws-provider-installer.yaml
  5. Delete AWS roles and policies by running the following command:

    $ aws iam detach-role-policy --role-name openshift-access-to-mysecret \
        --policy-arn $POLICY_ARN; aws iam delete-role --role-name openshift-access-to-mysecret; aws iam delete-policy --policy-arn $POLICY_ARN
  6. Delete the Secrets Manager secret by running the following command:

    $ aws secretsmanager --region $REGION delete-secret --secret-id $SECRET_ARN

Chapter 11. Tutorial: Use AWS Controllers for Kubernetes on Red Hat OpenShift Service on AWS

You can use AWS Controllers for Kubernetes (ACK) to manage AWS service resources directly from Red Hat OpenShift Service on AWS. With ACK, you don’t need to define resources outside of the cluster or run services that provide supporting capabilities.

You can install various ACK Operators directly from the software catalog to quickly integrate AWS services with your applications.

Follow this tutorial to deploy the ACK S3 Operator. You can also adapt these steps for any other ACK Operator in the catalog.

11.1. Set up your environment

Set environment variables to ensure consistency across the commands within this tutorial.

Prerequisites

  • You have created a Red Hat OpenShift Service on AWS cluster.
  • You have access to a user account with cluster-admin privileges.
  • You have access to the OpenShift CLI (oc).
  • You have access to the AWS CLI (aws).

Procedure

  1. Configure the following environment variables, changing the cluster name to suit your cluster:

    $ export CLUSTER_NAME=$(oc get infrastructure cluster -o=jsonpath="{.status.infrastructureName}"  | sed 's/-[a-z0-9]\{5\}$//')
    $ export REGION=$(rosa describe cluster -c ${ROSA_CLUSTER_NAME} --output json | jq -r .region.id)
    $ export OIDC_ENDPOINT=$(oc get authentication.config.openshift.io cluster -o json | jq -r .spec.serviceAccountIssuer | sed  's|^https://||')
    $ export AWS_ACCOUNT_ID=`aws sts get-caller-identity --query Account --output text`
    $ export ACK_SERVICE=s3
    $ export ACK_SERVICE_ACCOUNT=ack-${ACK_SERVICE}-controller
    $ export POLICY_ARN=arn:aws:iam::aws:policy/AmazonS3FullAccess
    $ export AWS_PAGER=""
    $ export SCRATCH="/tmp/${ROSA_CLUSTER_NAME}/ack"
    $ mkdir -p ${SCRATCH}
  2. Ensure all fields output correctly:

    $ echo "Cluster: ${ROSA_CLUSTER_NAME}, Region: ${REGION}, OIDC Endpoint: ${OIDC_ENDPOINT}, AWS Account ID: ${AWS_ACCOUNT_ID}"

11.2. Prepare your AWS account

Create the AWS Identity and Access Management (IAM) trust policy and role that the AWS Controllers for Kubernetes (ACK) Operator requires to manage AWS resources from your Red Hat OpenShift Service on AWS cluster.

Procedure

  1. Create an AWS IAM trust policy for the ACK Operator:

    $ cat <<EOF > "${SCRATCH}/trust-policy.json"
    {
     "Version": "2012-10-17",
     "Statement": [
     {
     "Effect": "Allow",
     "Condition": {
       "StringEquals" : {
         "${OIDC_ENDPOINT}:sub": "system:serviceaccount:ack-system:${ACK_SERVICE_ACCOUNT}"
       }
     },
     "Principal": {
       "Federated": "arn:aws:iam::$AWS_ACCOUNT_ID:oidc-provider/${OIDC_ENDPOINT}"
     },
     "Action": "sts:AssumeRoleWithWebIdentity"
     }
     ]
    }
    EOF
  2. Create an AWS IAM role for the ACK Operator to assume with the AmazonS3FullAccess policy attached:

    Note
    $ ROLE_ARN=$(aws iam create-role --role-name "ack-${ACK_SERVICE}-controller" \
       --assume-role-policy-document "file://${SCRATCH}/trust-policy.json" \
       --query Role.Arn --output text)
    $ echo $ROLE_ARN
    $ aws iam attach-role-policy --role-name "ack-${ACK_SERVICE}-controller" \
         --policy-arn ${POLICY_ARN}

11.3. Install the ACK S3 controller

Configure and deploy the AWS Controllers for Kubernetes (ACK) S3 controller by installing the ACK S3 Operator and associating it with an AWS Identity and Access Management (IAM) role.

Procedure

  1. Create a project to install the ACK S3 Operator into:

    $ oc new-project ack-system
  2. Create a file with the ACK S3 Operator configuration:

    Note

    ACK_WATCH_NAMESPACE is purposely left blank so the controller can properly watch all namespaces in the cluster.

    $ cat << EOF  "${SCRATCH}/config.txt"
    ACK_ENABLE_DEVELOPMENT_LOGGING=true
    ACK_LOG_LEVEL=debug
    ACK_WATCH_NAMESPACE=
    AWS_REGION=${REGION}
    AWS_ENDPOINT_URL=
    ACK_RESOURCE_TAGS=${CLUSTER_NAME}
    ENABLE_LEADER_ELECTION=true
    LEADER_ELECTION_NAMESPACE=
    RECONCILE_DEFAULT_MAX_CONCURRENT_SYNCS=1
    FEATURE_FLAGS=
    FEATURE_GATES=
    EOF
  3. Use the file from the previous step to create a ConfigMap:

    $ oc -n ack-system create configmap \
      --from-env-file=${SCRATCH}/config.txt ack-${ACK_SERVICE}-user-config
  4. Install the ACK S3 Operator from the software catalog:

    $ cat << EOF | oc apply -f -
    apiVersion: operators.coreos.com/v1
    kind: OperatorGroup
    metadata:
      name: ack-${ACK_SERVICE}-controller
      namespace: ack-system
    spec:
      upgradeStrategy: Default
    ---
    apiVersion: operators.coreos.com/v1alpha1
    kind: Subscription
    metadata:
      name: ack-${ACK_SERVICE}-controller
      namespace: ack-system
    spec:
      channel: alpha
      installPlanApproval: Automatic
      name: ack-${ACK_SERVICE}-controller
      source: community-operators
      sourceNamespace: openshift-marketplace
    EOF
  5. Annotate the ACK S3 Operator service account with the AWS IAM role to assume and restart the deployment:

    $ oc -n ack-system annotate serviceaccount ${ACK_SERVICE_ACCOUNT} \
      eks.amazonaws.com/role-arn=${ROLE_ARN} && \
      oc -n ack-system rollout restart deployment ack-${ACK_SERVICE}-controller

Verification

  1. Verify that the ACK S3 Operator is running:

    $ oc -n ack-system get pods

    Example output

    NAME                                 READY   STATUS    RESTARTS   AGE
    ack-s3-controller-585f6775db-s4lfz   1/1     Running   0          51s

11.4. Validate the deployment

Verify that the controller is working correctly by deploying a test S3 bucket resource and confirming that it is created in AWS.

Procedure

  1. Deploy an S3 bucket resource:

    $ cat << EOF | oc apply -f -
    apiVersion: s3.services.k8s.aws/v1alpha1
    kind: Bucket
    metadata:
       name: ${CLUSTER-NAME}-bucket
       namespace: ack-system
    spec:
       name: ${CLUSTER-NAME}-bucket
    EOF
  2. Verify the S3 bucket was created in AWS:

    $ aws s3 ls | grep ${CLUSTER_NAME}-bucket

    Example output

    2023-10-04 14:51:45 mrmc-test-maz-bucket

11.5. Clean up AWS resources

Clean up your AWS resources after completing this tutorial.

Procedure

  1. Delete the S3 bucket resource:

    $ oc -n ack-system delete bucket.s3.services.k8s.aws/${CLUSTER-NAME}-bucket
  2. Delete the AWS Controller for Kubernetes (ACK) S3 Operator and the AWS Identity and Access Management (IAM) roles:

    $ oc -n ack-system delete subscription ack-${ACK_SERVICE}-controller
    $ aws iam detach-role-policy \
      --role-name "ack-${ACK_SERVICE}-controller" \
      --policy-arn ${POLICY_ARN}
    $ aws iam delete-role \
      --role-name "ack-${ACK_SERVICE}-controller"
  3. Delete the ack-system project:

    $ oc delete project ack-system

11.6. Additional resources

Chapter 12. Tutorial: Assign a consistent egress IP for external traffic

You can configure a set of predictable IP addresses for egress cluster traffic. Assigning a consistent IP address for outbound cluster traffic is useful when external resources, such as security groups, require an IP-based configuration to meet security standards.

Note

By default, Red Hat OpenShift Service on AWS uses the OVN-Kubernetes container network interface (CNI) to assign random IP addresses from a pool. This can make configuring security lockdowns unpredictable or open.

12.1. Set environment variables

Set environment variables to ensure consistency across the commands in this tutorial.

Prerequisites

  • You have created a Red Hat OpenShift Service on AWS cluster deployed with OVN-Kubernetes.
  • You have access to the OpenShift CLI (oc).
  • You have access to the ROSA command-line interface (CLI) (rosa).
  • You have access to the jq command-line JSON processor.

Procedure

  • Set your environment variables by running the following command:

    Note

    Replace the value of the ROSA_MACHINE_POOL_NAME variable to target a different machine pool.

    $ export ROSA_CLUSTER_NAME=$(oc get infrastructure cluster -o=jsonpath="{.status.infrastructureName}"  | sed 's/-[a-z0-9]\{5\}$//')
    $ export ROSA_MACHINE_POOL_NAME=worker

12.2. Ensure IP address capacity

Confirm that your nodes have available IP address capacity. Each public cloud provider limits the number of IP addresses that you can assign to each node.

Procedure

  • Verify sufficient capacity by running the following command:

    $ oc get node -o json | \
        jq '.items[] |
            {
                "name": .metadata.name,
                "ips": (.status.addresses | map(select(.type == "InternalIP") | .address)),
                "capacity": (.metadata.annotations."cloud.network.openshift.io/egress-ipconfig" | fromjson[] | .capacity.ipv4)
            }'

    Example output

    {
      "name": "ip-10-10-145-88.ec2.internal",
      "ips": [
        "10.10.145.88"
      ],
      "capacity": 14
    }
    {
      "name": "ip-10-10-154-175.ec2.internal",
      "ips": [
        "10.10.154.175"
      ],
      "capacity": 14
    }

12.3. Create the egress IP rules

Configure egress IP rules to provide reserved, consistent IP addresses for your outbound cluster traffic. Before creating the egress IP rules, identify which egress IPs to use.

Note

The egress IPs that you select should exist as a part of the subnets in which the worker nodes are provisioned.

Procedure

12.4. Assign an egress IP to a namespace

Assign an egress IP to a namespace on your cluster to ensure that all pods inside it use a consistent, predictable address for external connections.

Procedure

  1. Create a new project by running the following command:

    $ oc new-project demo-egress-ns
  2. Create the egress rule for all pods within the namespace by running the following command:

    $ cat <<EOF | oc apply -f -
    apiVersion: k8s.ovn.org/v1
    kind: EgressIP
    metadata:
      name: demo-egress-ns
    spec:
      # NOTE: these egress IPs are within the subnet range(s) in which my worker nodes
      #       are deployed.
      egressIPs:
        - 10.10.100.253
        - 10.10.150.253
        - 10.10.200.253
      namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: demo-egress-ns
    EOF

12.5. Assign an egress IP to a pod

Create an egress rule to assign a consistent egress IP to a specified pod so that its outbound traffic uses a predictable IP.

Procedure

  1. Create a new project by running the following command:

    $ oc new-project demo-egress-pod
  2. Create the egress rule for the pod by running the following command:

    Note

    spec.namespaceSelector is a mandatory field.

    $ cat <<EOF | oc apply -f -
    apiVersion: k8s.ovn.org/v1
    kind: EgressIP
    metadata:
      name: demo-egress-pod
    spec:
      # NOTE: these egress IPs are within the subnet range(s) in which my worker nodes
      #       are deployed.
      egressIPs:
        - 10.10.100.254
        - 10.10.150.254
        - 10.10.200.254
      namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: demo-egress-pod
      podSelector:
        matchLabels:
          run: demo-egress-pod
    EOF

12.5.1. Label the nodes

Apply labels to worker nodes for egress IP assignments.

Procedure

  1. Obtain your pending egress IP assignments by running the following command:

    $ oc get egressips

    Example output

    NAME              EGRESSIPS       ASSIGNED NODE   ASSIGNED EGRESSIPS
    demo-egress-ns    10.10.100.253
    demo-egress-pod   10.10.100.254

    The egress IP rule that you created only applies to nodes with the k8s.ovn.org/egress-assignable label. Make sure that the label is only on a specific machine pool.

  2. Assign the label to your machine pool using the following command:

    Warning

    If you rely on node labels for your machine pool, this command will replace those labels. Be sure to input your desired labels into the --labels field to ensure your node labels remain.

    $ rosa update machinepool ${ROSA_MACHINE_POOL_NAME} \
      --cluster="${ROSA_CLUSTER_NAME}" \
      --labels "k8s.ovn.org/egress-assignable="

12.5.2. Review the egress IPs

Review egress IP assignments to verify that each egress IP address is correctly assigned to a node.

Procedure

  • Review the egress IP assignments by running the following command:

    $ oc get egressips

    Example output

    NAME              EGRESSIPS       ASSIGNED NODE                   ASSIGNED EGRESSIPS
    demo-egress-ns    10.10.100.253   ip-10-10-156-122.ec2.internal   10.10.150.253
    demo-egress-pod   10.10.100.254   ip-10-10-156-122.ec2.internal   10.10.150.254

12.5.3. Deploy a sample application

To test the egress IP rule, create a service that is restricted to the egress IP addresses that you specified. The service simulates an external service that expects a small subset of IP addresses.

Procedure

  1. Run the echoserver command to replicate a request:

    $ oc -n default run demo-service --image=gcr.io/google_containers/echoserver:1.4
  2. Expose the pod as a service and limit the ingress to the egress IP addresses you specified by running the following command:

    $ cat <<EOF | oc apply -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: demo-service
      namespace: default
      annotations:
        service.beta.kubernetes.io/aws-load-balancer-scheme: "internal"
        service.beta.kubernetes.io/aws-load-balancer-internal: "true"
    spec:
      selector:
        run: demo-service
      ports:
        - port: 80
          targetPort: 8080
      type: LoadBalancer
      externalTrafficPolicy: Local
      # NOTE: this limits the source IPs that are allowed to connect to our service.  It
      #       is being used as part of this demo, restricting connectivity to our egress
      #       IP addresses only.
      # NOTE: these egress IPs are within the subnet range(s) in which my worker nodes
      #       are deployed.
      loadBalancerSourceRanges:
        - 10.10.100.254/32
        - 10.10.150.254/32
        - 10.10.200.254/32
        - 10.10.100.253/32
        - 10.10.150.253/32
        - 10.10.200.253/32
    EOF
  3. Retrieve the load balancer hostname and save it as an environment variable by running the following command:

    $ export LOAD_BALANCER_HOSTNAME=$(oc get svc -n default demo-service -o json | jq -r '.status.loadBalancer.ingress[].hostname')

12.5.4. Test the namespace egress

Verify that your namespace egress IP configuration works correctly.

Procedure

  1. Start an interactive shell to test the namespace egress rule:

    $ oc run \
      demo-egress-ns \
      -it \
      --namespace=demo-egress-ns \
      --env=LOAD_BALANCER_HOSTNAME=$LOAD_BALANCER_HOSTNAME \
      --image=registry.access.redhat.com/ubi9/ubi -- \
      bash
  2. Send a request to the load balancer and ensure that you can successfully connect:

    $ curl -s http://$LOAD_BALANCER_HOSTNAME
  3. Check the output for a successful connection:

    Note

    The client_address is the internal IP address of the load balancer, not your egress IP. You can verify that you have configured the client address correctly by connecting with your service limited to .spec.loadBalancerSourceRanges.

    Example output

    CLIENT VALUES:
    client_address=10.10.207.247
    command=GET
    real path=/
    query=nil
    request_version=1.1
    request_uri=http://internal-a3e61de18bfca4a53a94a208752b7263-148284314.us-east-1.elb.amazonaws.com:8080/
    
    SERVER VALUES:
    server_version=nginx: 1.10.0 - lua: 10001
    
    HEADERS RECEIVED:
    accept=*/*
    host=internal-a3e61de18bfca4a53a94a208752b7263-148284314.us-east-1.elb.amazonaws.com
    user-agent=curl/7.76.1
    BODY:
    -no body in request-

  4. Exit the pod by running the following command:

    $ exit

12.5.5. Test the pod egress

Verify that your egress IP configuration works correctly.

Procedure

  1. Start an interactive shell to test the pod egress rule:

    $ oc run \
      demo-egress-pod \
      -it \
      --namespace=demo-egress-pod \
      --env=LOAD_BALANCER_HOSTNAME=$LOAD_BALANCER_HOSTNAME \
      --image=registry.access.redhat.com/ubi9/ubi -- \
      bash
  2. Send a request to the load balancer by running the following command:

    $ curl -s http://$LOAD_BALANCER_HOSTNAME
  3. Check the output for a successful connection:

    Note

    The client_address is the internal IP address of the load balancer, not your egress IP. You can verify that you have configured the client address correctly by connecting with your service limited to .spec.loadBalancerSourceRanges.

    Example output

    CLIENT VALUES:
    client_address=10.10.207.247
    command=GET
    real path=/
    query=nil
    request_version=1.1
    request_uri=http://internal-a3e61de18bfca4a53a94a208752b7263-148284314.us-east-1.elb.amazonaws.com:8080/
    
    SERVER VALUES:
    server_version=nginx: 1.10.0 - lua: 10001
    
    HEADERS RECEIVED:
    accept=*/*
    host=internal-a3e61de18bfca4a53a94a208752b7263-148284314.us-east-1.elb.amazonaws.com
    user-agent=curl/7.76.1
    BODY:
    -no body in request-

  4. Exit the pod by running the following command:

    $ exit

12.5.6. Test blocked egress

This procedure is optional. You can test if your egress IP configuration correctly blocks traffic.

Procedure

  1. Test that the traffic is successfully blocked when the egress rules do not apply by running the following command:

    $ oc run \
      demo-egress-pod-fail \
      -it \
      --namespace=demo-egress-pod \
      --env=LOAD_BALANCER_HOSTNAME=$LOAD_BALANCER_HOSTNAME \
      --image=registry.access.redhat.com/ubi9/ubi -- \
      bash
  2. Send a request to the load balancer by running the following command:

    $ curl -s http://$LOAD_BALANCER_HOSTNAME

    If the command is unsuccessful, egress is successfully blocked.

  3. Exit the pod by running the following command:

    $ exit

12.6. Clean up your cluster

Clean up your cluster environment after testing the egress IP configuration.

Procedure

  1. Clean up your cluster by running the following commands:

    $ oc delete svc demo-service -n default
    $ oc delete pod demo-service -n default
    $ oc delete project demo-egress-ns
    $ oc delete project demo-egress-pod
    $ oc delete egressip demo-egress-ns
    $ oc delete egressip demo-egress-pod
  2. Clean up the assigned node labels by running the following command:

    Warning

    If you rely on node labels for your machine pool, this command replaces those labels. Input your desired labels into the --labels field to ensure your node labels remain.

    $ rosa update machinepool ${ROSA_MACHINE_POOL_NAME} \
      --cluster="${ROSA_CLUSTER_NAME}" \
      --labels ""

Legal Notice

Copyright © Red Hat.
Except as otherwise noted below, the text of and illustrations in this documentation are licensed by Red Hat under the Creative Commons Attribution–Share Alike 3.0 Unported license . If you distribute this document or an adaptation of it, you must provide the URL for the original version.
Red Hat, as the licensor of this document, waives the right to enforce, and agrees not to assert, Section 4d of CC-BY-SA to the fullest extent permitted by applicable law.
Red Hat, the Red Hat logo, JBoss, Hibernate, and RHCE are trademarks or registered trademarks of Red Hat, LLC. or its subsidiaries in the United States and other countries.
Linux® is the registered trademark of Linus Torvalds in the United States and other countries.
XFS is a trademark or registered trademark of Hewlett Packard Enterprise Development LP or its subsidiaries in the United States and other countries.
The OpenStack® Word Mark and OpenStack logo are trademarks or registered trademarks of the Linux Foundation, used under license.
All other trademarks are the property of their respective owners.