---
title: Security
---

# Security {#ossm-security}

If your service mesh application is constructed with a complex array of microservices, you can use Red Hat OpenShift Service Mesh to customize the security of the communication between those services. The infrastructure of OpenShift Container Platform along with the traffic management features of Service Mesh help you manage the complexity of your applications and secure microservices.

**Before you begin**

If you have a project, add your project to the [`ServiceMeshMemberRoll` resource](/openshift-docs-markdown/service_mesh/v2x/ossm-create-mesh#ossm-member-roll-create_ossm-create-mesh).

If you don’t have a project, install the [Bookinfo sample application](/openshift-docs-markdown/service_mesh/v2x/ossm-create-mesh#ossm-tutorial-bookinfo-overview_ossm-create-mesh) and add it to the `ServiceMeshMemberRoll` resource. The sample application helps illustrate security concepts.

## About mutual Transport Layer Security (mTLS) {#ossm-security-mtls_ossm-security}

Mutual Transport Layer Security (mTLS) is a protocol that enables two parties to authenticate each other. It is the default mode of authentication in some protocols (IKE, SSH) and optional in others (TLS). You can use mTLS without changes to the application or service code. The TLS is handled entirely by the service mesh infrastructure and between the two sidecar proxies.

By default, mTLS in Red Hat OpenShift Service Mesh is enabled and set to permissive mode, where the sidecars in Service Mesh accept both plain-text traffic and connections that are encrypted using mTLS. If a service in your mesh configured to use strict mTLS is communicating with a service outside the mesh, communication might break between those services because strict mTLS requires both the client and the server to be able to verify the identify of each other. Use permissive mode while you migrate your workloads to Service Mesh. Then, you can enable strict mTLS across your mesh, namespace, or application.

Enabling mTLS across your mesh at the Service Mesh control plane level secures all the traffic in your service mesh without rewriting your applications and workloads. You can secure namespaces in your mesh at the data plane level in the `ServiceMeshControlPlane` resource. To customize traffic encryption connections, configure namespaces at the application level with `PeerAuthentication` and `DestinationRule` resources.

### Enabling strict mTLS across the service mesh {#ossm-security-enabling-strict-mtls_ossm-security}

If your workloads do not communicate with outside services, you can quickly enable mTLS across your mesh without communication interruptions. You can enable it by setting `spec.security.dataPlane.mtls` to `true` in the `ServiceMeshControlPlane` resource. The Operator creates the required resources.

```yaml
apiVersion: maistra.io/v2
kind: ServiceMeshControlPlane
spec:
  version: v2.6
  security:
    dataPlane:
      mtls: true
```

You can also enable mTLS by using the OpenShift Container Platform web console.

**Procedure**

1. Log in to the web console.
2. Click the **Project** menu and select the project where you installed the Service Mesh control plane, for example **istio-system**.
3. Click **Ecosystem** → **Installed Operators**.
4. Click **Service Mesh Control Plane** under **Provided APIs**.
5. Click the name of your `ServiceMeshControlPlane` resource, for example, `basic`.
6. On the **Details** page, click the toggle in the **Security** section for **Data Plane Security**.

#### Configuring sidecars for incoming connections for specific services {#ossm-security-mtls-sidecars-incoming-services_ossm-security}

You can also configure mTLS for individual services by creating a policy.

**Procedure**

1. Create a YAML file using the following example.

   ```yaml {title="PeerAuthentication Policy example policy.yaml"}
   apiVersion: security.istio.io/v1beta1
   kind: PeerAuthentication
   metadata:
     name: default
     namespace: <namespace>
   spec:
     mtls:
       mode: STRICT
   ```

   1. Replace `<namespace>` with the namespace where the service is located.
2. Run the following command to create the resource in the namespace where the service is located. It must match the `namespace` field in the Policy resource you just created.

   ```terminal
   $ oc create -n <namespace> -f <policy.yaml>
   ```

   > [!NOTE]
   > If you are not using automatic mTLS and you are setting `PeerAuthentication` to STRICT, you must create a `DestinationRule` resource for your service.

#### Configuring sidecars for outgoing connections {#ossm-security-mtls-sidecars-outgoing_ossm-security}

Create a destination rule to configure Service Mesh to use mTLS when sending requests to other services in the mesh.

**Procedure**

1. Create a YAML file using the following example.

   ```yaml {title="DestinationRule example destination-rule.yaml"}
   apiVersion: networking.istio.io/v1alpha3
   kind: DestinationRule
   metadata:
     name: default
     namespace: <namespace>
   spec:
     host: "*.<namespace>.svc.cluster.local"
     trafficPolicy:
      tls:
       mode: ISTIO_MUTUAL
   ```

   1. Replace `<namespace>` with the namespace where the service is located.
2. Run the following command to create the resource in the namespace where the service is located. It must match the `namespace` field in the `DestinationRule` resource you just created.

   ```terminal
   $ oc create -n <namespace> -f <destination-rule.yaml>
   ```

#### Setting the minimum and maximum protocol versions {#ossm-security-min-max-tls_ossm-security}

If your environment has specific requirements for encrypted traffic in your service mesh, you can control the cryptographic functions that are allowed by setting the `spec.security.controlPlane.tls.minProtocolVersion` or `spec.security.controlPlane.tls.maxProtocolVersion` in your `ServiceMeshControlPlane` resource. Those values, configured in your Service Mesh control plane resource, define the minimum and maximum TLS version used by mesh components when communicating securely over TLS.

The default is `TLS_AUTO` and does not specify a version of TLS.

**Valid values**

| Value | Description |
| --- | --- |
| `TLS_AUTO` | default |
| `TLSv1_0` | TLS version 1.0 |
| `TLSv1_1` | TLS version 1.1 |
| `TLSv1_2` | TLS version 1.2 |
| `TLSv1_3` | TLS version 1.3 |

**Procedure**

1. Log in to the web console.
2. Click the **Project** menu and select the project where you installed the Service Mesh control plane, for example **istio-system**.
3. Click **Ecosystem** → **Installed Operators**.
4. Click **Service Mesh Control Plane** under **Provided APIs**.
5. Click the name of your `ServiceMeshControlPlane` resource, for example, `basic`.
6. Click the **YAML** tab.
7. Insert the following code snippet in the YAML editor. Replace the value in the `minProtocolVersion` with the TLS version value. In this example, the minimum TLS version is set to `TLSv1_2`.

   ```yaml {title="ServiceMeshControlPlane snippet"}
   kind: ServiceMeshControlPlane
   spec:
     security:
       controlPlane:
         tls:
           minProtocolVersion: TLSv1_2
   ```
8. Click **Save**.
9. Click **Refresh** to verify that the changes updated correctly.

### Validating encryption with Kiali {#ossm-validating-sidecar_ossm-security}

The Kiali console offers several ways to validate whether or not your applications, services, and workloads have mTLS encryption enabled.

**Figure 1. Masthead icon mesh-wide mTLS enabled**

![mTLS enabled](/openshift-docs-markdown/images/ossm-kiali-masthead-mtls-enabled.png)

At the right side of the masthead, Kiali shows a lock icon when the mesh has strictly enabled mTLS for the whole service mesh. It means that all communications in the mesh use mTLS.

**Figure 2. Masthead icon mesh-wide mTLS partially enabled**

![mTLS partially enabled](/openshift-docs-markdown/images/ossm-kiali-masthead-mtls-partial.png)

Kiali displays a hollow lock icon when either the mesh is configured in `PERMISSIVE` mode or there is a error in the mesh-wide mTLS configuration.

**Figure 3. Security badge**

![Security badge](/openshift-docs-markdown/images/ossm-kiali-graph-badge-security.png)

The **Graph** page has the option to display a **Security** badge on the graph edges to indicate that mTLS is enabled.  To enable security badges on the graph, from the **Display** menu, under **Show Badges**, select the **Security** checkbox.  When an edge shows a lock icon, it means at least one request with mTLS enabled is present.  In case there are both mTLS and non-mTLS requests, the side-panel will show the percentage of requests that use mTLS.

The **Applications Detail Overview** page displays a **Security** icon on the graph edges where at least one request with mTLS enabled is present.

The **Workloads Detail Overview** page displays a **Security** icon on the graph edges where at least one request with mTLS enabled is present.

The **Services Detail Overview** page displays a **Security** icon on the graph edges where at least one request with mTLS enabled is present.  Also note that Kiali displays a lock icon in the **Network** section next to ports that are configured for mTLS.

## Configuring Role Based Access Control (RBAC) {#ossm-vs-istio_ossm-security}

Role-based access control (RBAC) objects determine whether a user or service is allowed to perform a given action within a project. You can define mesh-, namespace-, and workload-wide access control for your workloads in the mesh.

To configure RBAC, create an `AuthorizationPolicy` resource in the namespace for which you are configuring access. If you are configuring mesh-wide access, use the project where you installed the Service Mesh control plane, for example `istio-system`.

For example, with RBAC, you can create policies that:

- Configure intra-project communication.
- Allow or deny full access to all workloads in the default namespace.
- Allow or deny ingress gateway access.
- Require a token for access.

An authorization policy includes a selector, an action, and a list of rules:

- The `selector` field specifies the target of the policy.
- The `action` field specifies whether to allow or deny the request.
- The `rules` field specifies when to trigger the action.

  - The `from` field specifies constraints on the request origin.
  - The `to` field specifies constraints on request target and parameters.
  - The `when` field specifies additional conditions that to apply the rule.

**Procedure**

1. Create your `AuthorizationPolicy` resource. The following example shows a resource that updates the ingress-policy `AuthorizationPolicy` to deny an IP address from accessing the ingress gateway.

   ```yaml
   apiVersion: security.istio.io/v1beta1
   kind: AuthorizationPolicy
   metadata:
     name: ingress-policy
     namespace: istio-system
   spec:
     selector:
       matchLabels:
         app: istio-ingressgateway
     action: DENY
     rules:
     - from:
       - source:
           ipBlocks: ["1.2.3.4"]
   ```
2. Run the following command after you write your resource to create your resource in your namespace. The namespace must match your `metadata.namespace` field in your `AuthorizationPolicy` resource.

   ```terminal
   $ oc create -n istio-system -f <filename>
   ```

**Next steps**

Consider the following examples for other common configurations.

### Configure intra-project communication {#_configure_intra-project_communication}

You can use `AuthorizationPolicy` to configure your Service Mesh control plane to allow or deny the traffic communicating with your mesh or services in your mesh.

#### Restrict access to services outside a namespace {#_restrict_access_to_services_outside_a_namespace}

You can deny requests from any source that is not in the `bookinfo` namespace with the following `AuthorizationPolicy` resource example.

```yaml
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: httpbin-deny
 namespace: bookinfo
spec:
 selector:
   matchLabels:
     app: httpbin
     version: v1
 action: DENY
 rules:
 - from:
   - source:
       notNamespaces: ["bookinfo"]
```

#### Creating allow-all and default deny-all authorization policies {#_creating_allow-all_and_default_deny-all_authorization_policies}

The following example shows an allow-all authorization policy that allows full access to all workloads in the `bookinfo` namespace.

```yaml
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: allow-all
  namespace: bookinfo
spec:
  action: ALLOW
  rules:
  - {}
```

The following example shows a policy that denies any access to all workloads in the `bookinfo` namespace.

```yaml
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: deny-all
  namespace: bookinfo
spec:
  {}
```

### Allow or deny access to the ingress gateway {#_allow_or_deny_access_to_the_ingress_gateway}

You can set an authorization policy to add allow or deny lists based on IP addresses.

```yaml
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: ingress-policy
  namespace: istio-system
spec:
  selector:
    matchLabels:
      app: istio-ingressgateway
  action: ALLOW
  rules:
  - from:
    - source:
       ipBlocks: ["1.2.3.4", "5.6.7.0/24"]
```

### Restrict access with JSON Web Token {#_restrict_access_with_json_web_token}

You can restrict what can access your mesh with a JSON Web Token (JWT). After authentication, a user or service can access routes, services that are associated with that token.

Create a `RequestAuthentication` resource, which defines the authentication methods that are supported by a workload. The following example accepts a JWT issued by `http://localhost:8080/auth/realms/master`.

```yaml
apiVersion: "security.istio.io/v1beta1"
kind: "RequestAuthentication"
metadata:
  name: "jwt-example"
  namespace: bookinfo
spec:
  selector:
    matchLabels:
      app: httpbin
  jwtRules:
  - issuer: "http://localhost:8080/auth/realms/master"
    jwksUri: "http://keycloak.default.svc:8080/auth/realms/master/protocol/openid-connect/certs"
```

Then, create an `AuthorizationPolicy` resource in the same namespace to work with `RequestAuthentication` resource you created. The following example requires a JWT to be present in the `Authorization` header when sending a request to `httpbin` workloads.

```yaml
apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
  name: "frontend-ingress"
  namespace: bookinfo
spec:
  selector:
    matchLabels:
      app: httpbin
  action: DENY
  rules:
  - from:
    - source:
        notRequestPrincipals: ["*"]
```

## Configuring cipher suites and ECDH curves {#ossm-security-cipher_ossm-security}

Cipher suites and Elliptic-curve Diffie–Hellman (ECDH curves) can help you secure your service mesh. You can define a comma separated list of cipher suites using `spec.security.controlplane.tls.cipherSuites` and ECDH curves using `spec.security.controlplane.tls.ecdhCurves` in your `ServiceMeshControlPlane` resource. If either of these attributes are empty, then the default values are used.

The `cipherSuites` setting is effective if your service mesh uses TLS 1.2 or earlier. It has no effect when negotiating with TLS 1.3.

Set your cipher suites in the comma separated list in order of priority. For example, `ecdhCurves: CurveP256, CurveP384` sets `CurveP256` as a higher priority than `CurveP384`.

> [!NOTE]
> You must include either `TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256` or  `TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256` when you configure the cipher suite. HTTP/2 support requires at least one of these cipher suites.

The supported cipher suites are:

- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
- TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
- TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
- TLS_RSA_WITH_AES_128_CBC_SHA256
- TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA

The supported ECDH Curves are:

- CurveP256
- CurveP384
- CurveP521
- X25519

## Configuring JSON Web Key Sets resolver certificate authority {#ossm-configuring-jwks-resolver-ca_ossm-security}

You can configure your own JSON Web Key Sets (JWKS) resolver certificate authority (CA) from the `ServiceMeshControlPlane` (SMCP) spec.

**Procedure**

1. Edit the `ServiceMeshControlPlane` spec file:

   ```yaml
   $ oc edit smcp <smcp-name>
   ```
2. Enable `mtls` for the data plane by setting the value of the `mtls` field to `true` in the `ServiceMeshControlPlane` spec, as shown in the following example:

   ```yaml
   spec:
     security:
       dataPlane:
           mtls: true # enable mtls for data plane
       # JWKSResolver extra CA
       # PEM-encoded certificate content to trust an additional CA
       jwksResolverCA: |
           -----BEGIN CERTIFICATE-----
           [...]
           [...]
           -----END CERTIFICATE-----
   ...
   ```
3. Save the changes. OpenShift Container Platform automatically applies them.

A `ConfigMap` such as `pilot-jwks-cacerts-<SMCP name>` is created with the CA `.pem data`.

```yaml {title="Example ConfigMap pilot-jwks-cacerts-<SMCP name>"}
kind: ConfigMap
apiVersion: v1
data:
  extra.pem: |
      -----BEGIN CERTIFICATE-----
      [...]
      [...]
      -----END CERTIFICATE-----
```

## Adding an external certificate authority key and certificate {#ossm-cert-manage_ossm-security}

By default, Red Hat OpenShift Service Mesh generates a self-signed root certificate and key and uses them to sign the workload certificates. You can also use the user-defined certificate and key to sign workload certificates with user-defined root certificate. This task demonstrates an example to plug certificates and key into Service Mesh.

**Prerequisites**

- Install Red Hat OpenShift Service Mesh with mutual TLS enabled to configure certificates.
- This example uses the certificates from the [Maistra repository](https://github.com/maistra/istio/tree/maistra-2.6/samples/certs). For production, use your own certificates from your certificate authority.
- Deploy the Bookinfo sample application to verify the results with these instructions.
- OpenSSL is required to verify certificates.

### Adding an existing certificate and key {#ossm-cert-manage-add-cert-key_ossm-security}

To use an existing signing (CA) certificate and key, you must create a chain of trust file that includes the CA certificate, key, and root certificate. You must use the following exact file names for each of the corresponding certificates. The CA certificate is named `ca-cert.pem`, the key is `ca-key.pem`, and the root certificate, which signs `ca-cert.pem`, is named `root-cert.pem`. If your workload uses intermediate certificates, you must specify them in a `cert-chain.pem` file.

1. Save the example certificates from the [Maistra repository](https://github.com/maistra/istio/tree/maistra-2.6/samples/certs) locally and replace `<path>` with the path to your certificates.
2. Create a secret named `cacert` that includes the input files `ca-cert.pem`, `ca-key.pem`, `root-cert.pem` and `cert-chain.pem`.

   ```terminal
   $ oc create secret generic cacerts -n istio-system --from-file=<path>/ca-cert.pem \
       --from-file=<path>/ca-key.pem --from-file=<path>/root-cert.pem \
       --from-file=<path>/cert-chain.pem
   ```
3. In the `ServiceMeshControlPlane` resource set `spec.security.dataPlane.mtls true` to `true` and configure the `certificateAuthority` field as shown in the following example. The default `rootCADir` is `/etc/cacerts`. You do not need to set the `privateKey` if the key and certs are mounted in the default location.  Service Mesh reads the certificates and key from the secret-mount files.

   ```yaml
   apiVersion: maistra.io/v2
   kind: ServiceMeshControlPlane
   spec:
     security:
       dataPlane:
         mtls: true
       certificateAuthority:
         type: Istiod
         istiod:
           type: PrivateKey
           privateKey:
             rootCADir: /etc/cacerts
   ```
4. After creating/changing/deleting the `cacert` secret, the Service Mesh control plane `istiod` and `gateway` pods must be restarted so the changes go into effect. Use the following command to restart the pods:

   ```terminal
   $ oc -n istio-system delete pods -l 'app in (istiod,istio-ingressgateway, istio-egressgateway)'
   ```

   The Operator will automatically recreate the pods after they have been deleted.
5. Restart the bookinfo application pods so that the sidecar proxies pick up the secret changes. Use the following command to restart the pods:

   ```terminal
   $ oc -n bookinfo delete pods --all
   ```

   You should see output similar to the following:

   ```terminal
   pod "details-v1-6cd699df8c-j54nh" deleted
   pod "productpage-v1-5ddcb4b84f-mtmf2" deleted
   pod "ratings-v1-bdbcc68bc-kmng4" deleted
   pod "reviews-v1-754ddd7b6f-lqhsv" deleted
   pod "reviews-v2-675679877f-q67r2" deleted
   pod "reviews-v3-79d7549c7-c2gjs" deleted
   ```
6. Verify that the pods were created and are ready with the following command:

   ```terminal
   $ oc get pods -n bookinfo
   ```

### Verifying your certificates {#ossm-cert-manage-verify-cert_ossm-security}

Use the Bookinfo sample application to verify that the workload certificates are signed by the certificates that were plugged into the CA. This process requires that you have `openssl` installed on your machine.

1. To extract certificates from bookinfo workloads use the following command:

   ```terminal
   $ sleep 60
   ```

   ```terminal
   $ oc -n bookinfo exec "$(oc -n bookinfo get pod -l app=productpage -o jsonpath={.items..metadata.name})" -c istio-proxy -- openssl s_client -showcerts -connect details:9080 > bookinfo-proxy-cert.txt
   ```

   ```terminal
   $ sed -n '/-----BEGIN CERTIFICATE-----/{:start /-----END CERTIFICATE-----/!{N;b start};/.*/p}' bookinfo-proxy-cert.txt > certs.pem
   ```

   ```terminal
   $ awk 'BEGIN {counter=0;} /BEGIN CERT/{counter++} { print > "proxy-cert-" counter ".pem"}' < certs.pem
   ```

   After running the command, you should have three files in your working directory: `proxy-cert-1.pem`, `proxy-cert-2.pem` and `proxy-cert-3.pem`.
2. Verify that the root certificate is the same as the one specified by the administrator. Replace `<path>` with the path to your certificates.

   ```terminal
   $ openssl x509 -in <path>/root-cert.pem -text -noout > /tmp/root-cert.crt.txt
   ```

   Run the following syntax at the terminal window.

   ```terminal
   $ openssl x509 -in ./proxy-cert-3.pem -text -noout > /tmp/pod-root-cert.crt.txt
   ```

   Compare the certificates by running the following syntax at the terminal window.

   ```terminal
   $ diff -s /tmp/root-cert.crt.txt /tmp/pod-root-cert.crt.txt
   ```

   You should see the following result: `Files /tmp/root-cert.crt.txt and /tmp/pod-root-cert.crt.txt are identical`
3. Verify that the CA certificate is the same as the one specified by the administrator. Replace `<path>` with the path to your certificates.

   ```terminal
   $ openssl x509 -in <path>/ca-cert.pem -text -noout > /tmp/ca-cert.crt.txt
   ```

   Run the following syntax at the terminal window.

   ```terminal
   $ openssl x509 -in ./proxy-cert-2.pem -text -noout > /tmp/pod-cert-chain-ca.crt.txt
   ```

   Compare the certificates by running the following syntax at the terminal window.

   ```terminal
   $ diff -s /tmp/ca-cert.crt.txt /tmp/pod-cert-chain-ca.crt.txt
   ```

   You should see the following result: `Files /tmp/ca-cert.crt.txt and /tmp/pod-cert-chain-ca.crt.txt are identical.`
4. Verify the certificate chain from the root certificate to the workload certificate. Replace `<path>` with the path to your certificates. After you run the command, the expected output shows `./proxy-cert-1.pem: OK`.

   ```terminal
   $ openssl verify -CAfile <(cat <path>/ca-cert.pem <path>/root-cert.pem) ./proxy-cert-1.pem
   ```

### Removing the certificates {#ossm-cert-cleanup_ossm-security}

To remove the certificates you added, follow these steps.

1. Remove the secret `cacerts`. In this example, `istio-system` is the name of the Service Mesh control plane project.

   ```terminal
   $ oc delete secret cacerts -n istio-system
   ```
2. Redeploy Service Mesh with a self-signed root certificate in the `ServiceMeshControlPlane` resource.

   ```yaml
   apiVersion: maistra.io/v2
   kind: ServiceMeshControlPlane
   spec:
     security:
       dataPlane:
         mtls: true
   ```

## About integrating Service Mesh with cert-manager and istio-csr {#ossm-cert-manager-integration-istio_ossm-security}

The cert-manager tool is a solution for X.509 certificate management on Kubernetes. It delivers a unified API to integrate applications with private or public key infrastructure (PKI), such as Vault, Google Cloud Certificate Authority Service, Let’s Encrypt, and other providers.

The cert-manager tool ensures the certificates are valid and up-to-date by attempting to renew certificates at a configured time before they expire.

For Istio users, cert-manager also provides integration with `istio-csr`, which is a certificate authority (CA) server that handles certificate signing requests (CSR) from Istio proxies. The server then delegates signing to cert-manager, which forwards CSRs to the configured CA server.

> [!NOTE]
> Red Hat provides support for integrating with `istio-csr` and cert-manager. Red Hat does not provide direct support for the `istio-csr` or the community cert-manager components. The use of community cert-manager shown here is for demonstration purposes only.

**Prerequisites**

- One of these versions of cert-manager:

  - cert-manager Operator for Red Hat OpenShift 1.10 or later
  - community cert-manager Operator 1.11 or later
  - cert-manager 1.11 or later
- OpenShift Service Mesh Operator 2.4 or later
- `istio-csr` 0.6.0 or later

> [!NOTE]
> To avoid creating config maps in all namespaces when the `istio-csr` server is installed with the `jetstack/cert-manager-istio-csr` Helm chart, use the following setting: `app.controller.configmapNamespaceSelector: "maistra.io/member-of: <istio-namespace>"` in the `istio-csr.yaml` file.

### Installing cert-manager {#ossm-cert-manager-installation_ossm-security}

You can install the `cert-manager` tool to manage the lifecycle of TLS certificates and ensure that they are valid and up-to-date. If you are running Istio in your environment, you can also install the `istio-csr` certificate authority (CA) server, which handles certificate signing requests (CSR) from Istio proxies. The `istio-csr` CA delegates signing to the `cert-manager` tool, which delegates to the configured CA.

**Procedure**

1. Create the root cluster issuer:

   1. Create the `cluster-issuer` object as in the following example:

      ```yaml {title="Example cluster-issuer.yaml"}
      apiVersion: cert-manager.io/v1
      kind: Issuer
      metadata:
        name: selfsigned-root-issuer
        namespace: cert-manager
      spec:
        selfSigned: {}
      ---
      apiVersion: cert-manager.io/v1
      kind: Certificate
      metadata:
        name: root-ca
        namespace: cert-manager
      spec:
        isCA: true
        duration: 21600h # 900d
        secretName: root-ca
        commonName: root-ca.my-company.net
        subject:
          organizations:
          - my-company.net
        issuerRef:
          name: selfsigned-root-issuer
          kind: Issuer
          group: cert-manager.io
      ---
      apiVersion: cert-manager.io/v1
      kind: ClusterIssuer
      metadata:
        name: root-ca
      spec:
        ca:
          secretName: root-ca
      ```

      The namespace of the `selfsigned-root-issuer` issuer and `root-ca` certificate is `cert-manager` because `root-ca` is a cluster issuer, so the cert-manager looks for a referenced secret in its own namespace. The namespace is called `cert-manager` in the case of the cert-manager Operator for Red Hat OpenShift.
2. Create the object by using the following command:

   ```terminal
   $ oc apply -f cluster-issuer.yaml
   ```
3. Create the `istio-ca` object as in the following example:

   ```yaml {title="Example istio-ca.yaml"}
   apiVersion: cert-manager.io/v1
   kind: Certificate
   metadata:
     name: istio-ca
     namespace: istio-system
   spec:
     isCA: true
     duration: 21600h
     secretName: istio-ca
     commonName: istio-ca.my-company.net
     subject:
       organizations:
       - my-company.net
     issuerRef:
       name: root-ca
       kind: ClusterIssuer
       group: cert-manager.io
   ---
   apiVersion: cert-manager.io/v1
   kind: Issuer
   metadata:
     name: istio-ca
     namespace: istio-system
   spec:
     ca:
       secretName: istio-ca
   ```
4. Use the following command to create the object:

   ```terminal
   $ oc apply -n istio-system -f istio-ca.yaml
   ```

   1. Install `istio-csr`:

      ```terminal
      $ helm install istio-csr jetstack/cert-manager-istio-csr \
          -n istio-system \
          -f deploy/examples/cert-manager/istio-csr/istio-csr.yaml
      ```

      ```yaml {title="Example istio-csr.yaml"}
      replicaCount: 2

      image:
        repository: quay.io/jetstack/cert-manager-istio-csr
        tag: v0.6.0
        pullSecretName: ""

      app:
        certmanager:
          namespace: istio-system
          issuer:
            group: cert-manager.io
            kind: Issuer
            name: istio-ca

        controller:
          configmapNamespaceSelector: "maistra.io/member-of=istio-system"
          leaderElectionNamespace: istio-system

        istio:
          namespace: istio-system
          revisions: ["basic"]

        server:
          maxCertificateDuration: 5m

        tls:
          certificateDNSNames:
          # This DNS name must be set in the SMCP spec.security.certificateAuthority.cert-manager.address
          - cert-manager-istio-csr.istio-system.svc
      ```
   2. Deploy SMCP:

      ```terminal
      $ oc apply -f mesh.yaml -n istio-system
      ```

      ```yaml {title="Example mesh.yaml"}
      apiVersion: maistra.io/v2
      kind: ServiceMeshControlPlane
      metadata:
        name: basic
      spec:
        addons:
          grafana:
            enabled: false
          kiali:
            enabled: false
          prometheus:
            enabled: false
        proxy:
          accessLogging:
            file:
              name: /dev/stdout
        security:
          certificateAuthority:
            cert-manager:
              address: cert-manager-istio-csr.istio-system.svc:443
            type: cert-manager
          dataPlane:
            mtls: true
          identity:
            type: ThirdParty
        tracing:
          type: None
      ---
      apiVersion: maistra.io/v1
      kind: ServiceMeshMemberRoll
      metadata:
        name: default
      spec:
        members:
        - httpbin
        - sleep
      ```

      `security.identity.type: ThirdParty` must be set when `security.certificateAuthority.type: cert-manager` is configured.

**Verification**

Use the sample `httpbin` service and `sleep` app to check mTLS traffic from ingress gateways and verify that the `cert-manager` tool is installed.

1. Deploy the HTTP and `sleep` apps:

   ```terminal
   $ oc new-project <namespace>
   ```

   ```terminal
   $ oc apply -f https://raw.githubusercontent.com/maistra/istio/maistra-2.4/samples/httpbin/httpbin.yaml
   ```

   ```terminal
   $ oc apply -f https://raw.githubusercontent.com/maistra/istio/maistra-2.4/samples/sleep/sleep.yaml
   ```
2. Verify that `sleep` can access the `httpbin` service:

   ```terminal
   $ oc exec "$(oc get pod -l app=sleep -n <namespace> \
      -o jsonpath={.items..metadata.name})" -c sleep -n <namespace> -- \
      curl http://httpbin.<namespace>:8000/ip -s -o /dev/null \
      -w "%{http_code}\n"
   ```

   ```terminal {title="Example output"}
   200
   ```
3. Check mTLS traffic from the ingress gateway to the `httpbin` service:

   ```terminal
   $ oc apply -n <namespace> -f https://raw.githubusercontent.com/maistra/istio/maistra-2.4/samples/httpbin/httpbin-gateway.yaml
   ```
4. Get the `istio-ingressgateway` route:

   ```terminal
   INGRESS_HOST=$(oc -n istio-system get routes istio-ingressgateway -o jsonpath='{.spec.host}')
   ```
5. Verify mTLS traffic from the ingress gateway to the `httpbin` service:

   ```terminal
   $ curl -s -I http://$INGRESS_HOST/headers -o /dev/null -w "%{http_code}" -s
   ```

## Additional resources {#additional-resources_cert-manager-operator-red-hat-openshift ._additional-resources}

For information about how to install the cert-manager Operator for OpenShift Container Platform, see: [Installing the cert-manager Operator for Red Hat OpenShift](/openshift-docs-markdown/security/cert_manager_operator/cert-manager-operator-install).
