Set up the Ping application and Egress firewall inside Red Hat OpenShift Container Platform

As part of our scenario, we will set up egress firewall rules on top of the Ping application in Red Hat OpenShift Container Platform (OCP). In this we will explain how to deploy the ping application and how to apply an egress firewall to allow external communication only to the VM where the database is hosted.

Create the Ping application

This application is for testing purposes only. It connects to the IBM Db2 database and queries for the data stored in the table.

Note: If you only want to use the application deployed as a container, you can skip the first four steps and start with Step 5.
  1. Create a virtual environment for Python:

    python3 -m venv .
  2. Activate the virtual environment:

    source ./bin/activate
  3. Install python3-devel packages via pip:

    dnf install python3-devel
  4. Install IBM Db2 packages via pip:

    pip3 install ibm_db
  5. Create Python script in the name of ping_app.pyand provide the DB2 connection details.

    import ibm_db
    import sys
    import logging
    import time
    # Configure logging
    logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
    # DB2 connection details
    DB_HOST = #IP where the database is hosted#
    DB_PORT = #IBM DB2 port number, default port 25010#
    DB_NAME = "lpardb"
    DB_USER = #IBM DB2 User#
    DB_PASSWORD = #IBM DB2 Password#
    
    def ping_db2():
        conn_str = (
            f"DATABASE={DB_NAME};"
            f"HOSTNAME={DB_HOST};"
            f"PORT={DB_PORT};"
            f"PROTOCOL=TCPIP;"
            f"UID={DB_USER};"
            f"PWD={DB_PASSWORD};"
        )
        try:
            logging.info("Attempting to connect to Db2...")
            conn = ibm_db.connect(conn_str, "", "")
            logging.info("Connection to Db2 successful!")
            read_db2(conn)
            ibm_db.close(conn)
        except Exception as e:
            logging.error("Connection failed.")
            logging.error(f"Error: {e}")
            sys.exit(1)
    
    def read_db2(conn):
        query = "SELECT * FROM EMPLOYEES"
        try:
            logging.info(f"Executing query: {query}")
            stmt = ibm_db.exec_immediate(conn, query)
            result = ibm_db.fetch_both(stmt)
            if result:
                logging.info(f"Result: {result}")
            else:
                logging.warning("No results returned.")
        except Exception as e:
            logging.error("Failed to execute query.")
            logging.error(f"Error: {e}")
            sys.exit(2)
    
    if __name__ == "__main__":
        ping_db2()
        logging.info("Script completed. Now keeping the pod alive...")
        try:
            while True:
                time.sleep(60)  # Sleep indefinitely in 1-minute intervals
        except KeyboardInterrupt:
            logging.info("Received interrupt. Exiting.")
            sys.exit(0)

Deploy the Ping application in Red Hat OpenShift Container Platform

To create and deploy a container (based on the Python application) in Red Hat OpenShift Container Platform (OCP), follow these steps:

  1. In this scenario, the Dockerfile is created in the directory called ocp_dockerfiles which is used in the image creation:

    FROM registry.redhat.io/rhel9/s2i-base:9.5@sha256:51aed3869e0388a39465d933ef30f74f9d1b7267c3cf5956aa398186e333bb3b
    WORKDIR /app
    RUN dnf install -y python3 libxcrypt-compat python3-pip python3-devel bash && \
    dnf clean all
    RUN pip install ibm_db
    COPY ping_app.py .
    CMD ["python3","ping_app.py"]

    Optional verification: Create the container via podman:

    podman build -t ping_app .

    If it does not build correctly, adjust your Dockerfile accordingly.

  2. Create a new namespace in the OCP Web interface:

    Namespace name:db2-ping-app-1
    Note: In our scenario, we will install two ping apps in two different namespaces, namely db2-ping-app-1 and db2-ping-app-2. Change the correct namespace name accordingly as per your setup for all steps.
  3. Create imagestream.yaml:

    kind: ImageStream
    apiVersion: image.openshift.io/v1
    metadata:
      name: db2-ping-app-icic-imagestream
      namespace: db2-ping-app-1
    spec:
      lookupPolicy:
        local: true
  4. Apply imagestream.yaml from the bastion via the OCP cli:

    oc apply -f ./imagestream.yaml -n db2-ping-app-1
  5. Create buildconfig.yaml:

    kind: BuildConfig
    apiVersion: build.openshift.io/v1
    metadata:
      name: db2-ping-app-icic-buildconfig
      namespace: db2-ping-app-1
    spec:
      serviceAccount: builder
      nodeSelector: null
      output:
        to:
            name: 'db2-ping-app-icic-imagestream:latest'
    resources: {}
    successfulBuildsHistoryLimit: 2
    failedBuildsHistoryLimit: 2
    strategy:
        type: Docker
        dockerStrategy:
        dockerfilePath: Dockerfile
    postCommit: {}
    source:
        type: binary
        binary: {}
    runPolicy: Serial
    status:
    lastVersion: 0
  6. Apply buildconfig.yaml:

    oc apply -f ./buildconfig.yaml -n db2-ping-app-1
  7. Build and upload the container image to OCP:

    oc start-build --from-dir <directory of docker file> <build config name> -n <ping app namespace>

    Sample command:

    oc start-build --from-dir ocp_dockerfiles db2-ping-app-icic-buildconfig -n db2-ping-app-1

    Verify that the build completed successfully and was created. In the OCP Web interface, go to the Administrator view, click Builds, then select Builds again. The build is listed under the name of your build configuration in the namespace you created.

  8. Deploy the build as a pod in OCP.
    1. Get your build name:

      oc get builds 
      NAME                              TYPE     FROM     STATUS     STARTED          DURATION
      db2-ping-app-icic-buildconfig   Docker   Binary   Complete   24 minutes ago   58s

      where db2-ping-app-icic-buildconfig is your build name

    2. Get build ID via Image Digest:
      oc describe builds db2-ping-app-icic-buildconfig

      where sha256:d51e25d4bad05fb420ae6efe86f2b48ae03748fd6e12d75b72f6911e7b5ccac9i is the build ID

    3. Create a deployment YAML file called ping_app_pod_deployment.yaml and update the image ID and the build name
      apiVersion: apps/v1
      kind: Deployment
      metadata:
      name: my-app
      namespace: <namespace of your ping app>
      spec:
      replicas: 1
      selector:
          matchLabels:
          app: my-app
      template:
          metadata:
          labels:
              app: my-app
          spec:
          containers:
              - name: my-container
              image: <Image registy url>/<namespace>/<imagestream name>@<Build id>
              ports:
                  - containerPort: 8080

      Sample YAML file:

      apiVersion: apps/v1
      kind: Deployment
      metadata:
      name: my-app
      namespace: db2-ping-app-1  # Replace with your actual namespace
      spec:
      replicas: 1
      selector:
          matchLabels:
          app: my-app
      template:
          metadata:
          labels:
              app: my-app
          spec:
          containers:
              - name: my-container
              image: image-registry.openshift-image-registry.svc:5000/db2-ping-app-1/db2-ping-app-icic-imagestream@sha256:d51e25d4bad05fb420ae6efe86f2b48ae03748fd6e12d75b72f6911e7b5ccac9i # Replace it with the build generated from the previous step
              ports:
                  - containerPort: 8080
  9. Deploy the pod by running the following command:
    oc apply -f ping_app_pod_deployment.yaml -n db2-ping-app-1
  10. Verify a pod with the name my-app-XXX is created and is running in the OCP Web interface under Workloads, then Pods under db2-ping-app-1 namespace.

Apply the egress firewall

Apply an egress firewall to the db2-ping-app-1 namespace to allow the Ping application to communicate only with the IBM CIC virtual machine where the IBM Db2 database is hosted.

The official documentation can be found here.

  1. Create an egressfirewall.yaml file:

    apiVersion: k8s.ovn.org/v1
    kind: EgressFirewall
    metadata:
    name: default
    namespace: db2-ping-app-1
    spec:
    egress:
    - to:
        cidrSelector: #IBMCIC_VM_IP#/32
        type: Allow
    - to:
        cidrSelector: 0.0.0.0/0
        type: Deny
    Note: Specify the IP address of the host where the IBM Db2 database is installed under cidrSelector, and set the appropriate namespace for the Ping application in your configuration.
  2. Apply egress rules with the following command:

    oc apply -f egressfirewall.yaml -n db2-ping-app-1

    Verify the availability of egress rules in OCP by running the following cli command:

    oc get egressfirewall
    NAME      EGRESSFIREWALL STATUS
    default   EgressFirewall Rules applied

    Make sure that Status is set to Rules applied.

    The egress rules are now applied.