Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: add wum change note
Warning

This is available only as a  WUM update and is effective from 22nd October 2018 (2018-10-22). For more information on updating WSO2 API Manager, see Updating WSO2 API Manager.

In contrast to the usual one-way SSL authentication where a client verifies the identity of the server, in Mutual SSL the server validates the identity of the client so that both parties trust each other. This builds a system that has a very tight security and avoids any requests made to the client to provide the username/password, as long as the server is aware of the certificates that belong to the client. 

This section explains how APIs in WSO2 API Manager can be secured using Mutual SSL in addition to OAuth2.

Table of Contents
maxLevel3
minLevel3

Enable securing APIs with Mutual SSL

Follow the steps below to enable this feature in WSO2 API Manager.

Create the  AM_API_CLIENT_CERTIFICATE table in the APIM DB using the appropriate script given below. Note that the database name will depend on the databases present in your environment. 

...

activetrue
idH2
titleH2

...

Warning

This is available only as a  WUM update and is effective from 22nd October 2018 (2018-10-22). For more information on updating WSO2 API Manager, see Updating WSO2 API Manager.

In contrast to the usual one-way SSL authentication where a client verifies the identity of the server, in Mutual SSL the server validates the identity of the client so that both parties trust each other. This builds a system that has a very tight security and avoids any requests made to the client to provide the username/password, as long as the server is aware of the certificates that belong to the client. 

This section explains how APIs in WSO2 API Manager can be secured using Mutual SSL in addition to OAuth2.

Table of Contents
maxLevel3
minLevel3

Enable securing APIs with Mutual SSL

Follow the steps below to enable this feature in WSO2 API Manager.

  1. Create the  AM_API_CLIENT_CERTIFICATE table in the APIM DB using the appropriate script given below. Note that the database name will depend on the databases present in your environment. 

    Localtabgroup
    Localtab
    activetrue
    idH2
    titleH2
    Code Block
    CREATE TABLE IF NOT EXISTS `AM_API_CLIENT_CERTIFICATE` (
     `TENANT_ID` INT(11) NOT NULL,
     `ALIAS` VARCHAR(45) NOT NULL,
     `API_ID` INTEGER NOT NULL,
     `CERTIFICATE` BLOB NOT NULL,
     `REMOVED` BOOLEAN NOT NULL DEFAULT 0,
     `TIER_NAME` VARCHAR (512),
     FOREIGN KEY (API_ID) REFERENCES AM_API (API_ID) ON DELETE CASCADE ON UPDATE CASCADE,
     PRIMARY KEY (`ALIAS`,`TENANT_ID`, `REMOVED`)
    );
    Localtab
    idMSSQL
    titleMSSQL
    Code Block
    IF NOT  EXISTS (SELECT * FROM SYS.OBJECTS WHERE OBJECT_ID = OBJECT_ID(N'[DBO].[AM_API_CLIENT_CERTIFICATE]') AND TYPE IN (N'U'))
    CREATE TABLE AM_API_CLIENT_CERTIFICATE (
       TENANT_ID INTEGER NOT NULL,
       ALIAS VARCHAR(45) NOT NULL,
       API_ID INTEGER NOT NULL,
       CERTIFICATE VARBINARY(MAX) NOT NULL,
       REMOVED BIT NOT NULL DEFAULT 0,
       TIER_NAME VARCHAR(512),
       PRIMARY KEY (ALIAS, TENANT_ID, REMOVED),
       FOREIGN KEY (API_ID) REFERENCES AM_API(API_ID) ON DELETE CASCADE
    );
    Localtab
    idMySQL
    titleMySQL
    Code Block
    CREATE TABLE IF NOT EXISTS `AM_API_CLIENT_CERTIFICATE` (
     `TENANT_ID` INT(11) NOT NULL,
     `ALIAS` VARCHAR(45) NOT NULL,
     `API_ID` INTEGER NOT NULL,
     `CERTIFICATE` BLOB NOT NULL,
     `REMOVED` BOOLEAN NOT NULL DEFAULT 0,
     `TIER_NAME` VARCHAR (512),
     FOREIGN KEY (API_ID) REFERENCES AM_API (API_ID) ON DELETE CASCADE ON UPDATE CASCADE,
     PRIMARY KEY (`ALIAS`, `TENANT_ID`, `REMOVED`)
    ) ENGINE=InnoDB;
    Localtab
    idMySQLC
    titleMySQL Cluster
    Code Block
    CREATE TABLE IF NOT EXISTS `AM_API_CLIENT_CERTIFICATE` (
     `TENANT_ID` INT(11) NOT NULL,
     `ALIAS` VARCHAR(45) NOT NULL,
     `API_ID` INTEGER NOT NULL,
     `CERTIFICATE` BLOB NOT NULL,
     `REMOVED` BOOLEAN NOT NULL DEFAULT 0,
     `TIER_NAME` VARCHAR (512),
     FOREIGN KEY (API_ID) REFERENCES AM_API (API_ID) ON DELETE CASCADE,
     PRIMARY KEY (`ALIAS`, `TENANT_ID`, `REMOVED`)
    ) ENGINE=NDB;
    Localtab
    idOracle
    titleOracle
    Code Block
    CREATE TABLE AM_API_CLIENT_CERTIFICATE (
     TENANT_ID INTEGER NOT NULL,
     ALIAS VARCHAR2(45) NOT NULL,
     API_ID INTEGER NOT NULL,
     CERTIFICATE BLOB NOT NULL,
     REMOVED INTEGER DEFAULT 0 NOT NULL,
     TIER_NAME VARCHAR2 (512),
     FOREIGN KEY (API_ID) REFERENCES AM_API (API_ID) ON DELETE CASCADE,
     PRIMARY KEY (ALIAS, TENANT_ID, REMOVED)
    )
    /
    Localtab
    idOracleR
    titleOracle_rac
    Code Block
    CREATE TABLE AM_API_CLIENT_CERTIFICATE (
     TENANT_ID INTEGER NOT NULL,
     ALIAS VARCHAR2(45) NOT NULL,
     API_ID INTEGER NOT NULL,
     CERTIFICATE BLOB NOT NULL,
     REMOVED INTEGER DEFAULT 0 NOT NULL,
     TIER_NAME VARCHAR2(512),
     FOREIGN KEY (API_ID) REFERENCES AM_API (API_ID) ON DELETE CASCADE,
     PRIMARY KEY (ALIAS, TENANT_ID, REMOVED)
    )
    /
    Localtab
    idPostgreSQL
    titlePostgreSQL
    Code Block
    DROP TABLE IF EXISTS AM_API_CLIENT_CERTIFICATE;
    CREATE TABLE AM_API_CLIENT_CERTIFICATE (
     TENANT_ID INTEGER NOT NULL,
     ALIAS VARCHAR(45) NOT NULL,
     API_ID INTEGER NOT NULL,
     CERTIFICATE BYTEA NOT NULL,
     REMOVED BOOLEAN NOT NULL DEFAULT '0',
     TIER_NAME VARCHAR(512),
     FOREIGN KEY (API_ID) REFERENCES AM_API (API_ID) ON DELETE CASCADE,
     PRIMARY KEY (ALIAS, TENANT_ID, REMOVED)
    );
    Localtab
    idDB2
    titleDB2
    Code Block
    CREATE TABLE AM_API_CLIENT_CERTIFICATE (
      TENANT_ID INT NOT NULL,
      ALIAS VARCHAR(45) NOT NULL,
      API_ID INTEGER NOT NULL,
      CERTIFICATE BLOB NOT NULL,
      REMOVED SMALLINT NOT NULL DEFAULT 0,
      TIER_NAME VARCHAR (512),
      FOREIGN KEY (API_ID) REFERENCES AM_API (API_ID) ON DELETE CASCADE ON UPDATE CASCADE,
      PRIMARY KEY (ALIAS, TENANT_ID, REMOVED)
    )/
  2. Open the  <API-M_HOME>/repository/conf/axis2/axis2.xml file. Locate the transportReceiver for https as shown below.

    Code Block
    <transportReceiver name="https" class="org.apache.synapse.transport.passthru.PassThroughHttpSSLListener">

    Change the class name to  org.apache.synapse.transport.passthru.PassThroughHttpMultiSSLListener. The sample is given below.

    Code Block
    <transportReceiver name="https" class="org.apache.synapse.transport.passthru.PassThroughHttpMultiSSLListener">


  3. Add the following parameters under transportReceiver similar to the sample given below.

    Code Block
    <parameter name="dynamicSSLProfilesConfig">
    	<filePath>repository/resources/security/listenerprofiles.xml</filePath>
    	<fileReadInterval>600000</fileReadInterval>
    </parameter>
    <parameter name="SSLVerifyClient">optional</parameter>

    The dynamicSSLProfilesConfig specifies the file read to load the dynamic SSL profile and the time interval in which it will be read. 
    Note that if the fileReadInterval parameter is set to 600000, it will take at least 10 minutes for the gateway to accept a newly added client certificate.

    Expand
    titleExpand to see the transportReceiver segment after the changes mentioned above have been made...
    Code Block
    <transportReceiver name="https" class="org.apache.synapse.transport.passthru.PassThroughHttpMultiSSLListener">
            <parameter name="port" locked="false">8243</parameter>
            <parameter name="non-blocking" locked="false">true</parameter>
            <!--parameter name="bind-address" locked="false">hostname or IP address</parameter-->
            <!--parameter name="WSDLEPRPrefix" locked="false">https://apachehost:port/somepath</parameter-->
           <parameter name="httpGetProcessor" locked="false">org.wso2.carbon.mediation.transport.handlers.PassThroughNHttpGetProcessor</parameter>
            <parameter name="keystore" locked="false">
                <KeyStore>
                    <Location>repository/resources/security/wso2carbon.jks</Location>
                    <Type>JKS</Type>
                    <Password>wso2carbon</Password>
                    <KeyPassword>wso2carbon</KeyPassword>
                </KeyStore>
            </parameter>
            <parameter name="truststore" locked="false">
                <TrustStore>
                    <Location>repository/resources/security/client-truststore.jks</Location>
                    <Type>JKS</Type>
                    <Password>wso2carbon</Password>
                </TrustStore>
            </parameter>
           <!-- ============================================== -->
           <!-- Configuration for Listener Dynamic SSL Profile loading. -->
           <!-- Configured for 10 mins. -->
           <!-- ============================================== -->
           <parameter name="dynamicSSLProfilesConfig">
               <filePath>repository/resources/security/listenerprofiles.xml</filePath>
               <fileReadInterval>600000</fileReadInterval>
           </parameter>
           <parameter name="SSLVerifyClient">optional</parameter>
            <!--<parameter name="SSLVerifyClient">require</parameter>
                supports optional|require or defaults to none -->
    </transportReceiver>
  4. Copy the code given below to create the  listenerprofiles.xml file in the  <API-M_HOME>/repository/resources/security directory.

    Code Block
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <parameter name="SSLProfiles">
    <profile>
            <bindAddress>0.0.0.0</bindAddress>
             <KeyStore>
                <Location>repository/resources/security/wso2carbon.jks</Location>
                <Type>JKS</Type>
                <Password>wso2carbon</Password>
                <KeyPassword>wso2carbon</KeyPassword>
            </KeyStore>
            <TrustStore>
                <Location>repository/resources/security/client-truststore.jks</Location>
                <Type>JKS</Type>
            <Type>JKS</Type>
                <Password>wso2carbon</Password>
                <KeyPassword>wso2carbon</KeyPassword>
            </KeyStore>
            <TrustStore>
                <Location>repository/resources/security/client-truststore.jks</Location>
                <Type>JKS</Type>
                <Password>wso2carbon</Password>
            </TrustStore>
            <SSLVerifyClient>optional</SSLVerifyClient>
        </profile>
    </parameter>


    Note

    The  <API-M_HOME>/repository/resources/security directory can be changed according to the file path you have configured in Step 2.

  5. Open the <API-M_HOME>/repository/conf/api-manager.xml file. Set the  EnableMTLSForAPIs parameter to true.

    Code Block
    <APIManager>
    	...
      <EnableMTLSForAPIs>true</EnableMTLSForAPIs>
  6. Restart the server.

Create an API secured with Mutual SSL

  1. Create an API.
  2. Edit the API and navigate to the Manage tab.
  3. Select Mutual SSL under API Security.
    Image Added

    Note

    You can select both OAuth2 and Mutual SSL options. This means that the user can access the API using a valid OAuth2 token or using a valid client certificate. When OAuth2 and Mutual SSL are both enabled, Mutual SSL authentication will have a higher priority than OAuth2 as explained as follows:

    API SecurityUser's ResponseOutcome
    OAuth2Mutual SSL

    OAuth2
    token

    Mutual SSL
    Certificate

    EnabledEnabledSentSent
    • Initially, the Mutual SSL certificate is validated. If the validation is successful, the OAuth2 token is ignored.
    • If the Mutual SSL certificate fails, the OAuth2 token is validated, but if the OAuth2 token fails as well, the API call will fail.
    EnabledEnabledNot sentSent
    • The Mutual SSL certificate is validated. If the validation fails, the API call will fail.
    EnabledEnabledSentNot sent
    • The OAuth2 token is validated. If the validation fails, the API call will fail.
  4. Click Manage Certificates to upload a new client certificate. Select Add New Certificate.

    Image Added

    Insert excerpt
    Dynamic SSL Certificate Installation
    Dynamic SSL Certificate Installation
    nopaneltrue

    Info

    After configuring, the certificate will be added to the Gateway nodes which are defined under the Environments in api-manager.xml. In a clustered setup, as gateway configurations are identical, sync the <API-M_HOME>/repository/resources/security/listenerprofiles.xml and <API-M_HOME>/repository/resources/security/client-truststore.jks among the gateway nodes. After the configured interval, the synapse transport will be reloaded in all the gateway nodes.

  5. Provide an alias and public certificate. Select the tier that should be used to throttle out the calls using this particular client certificate and click Upload.
    Image Added

    Note
    titleIf you are marking the API as the Default Version
    Warning

    This is available only as a  WUM update and is effective from 15th July 2020 (2020-07-15). For more information on updating WSO2 API Manager, see Updating WSO2 API Manager.

    To make Mutual SSL work with Default APIs follow the below steps before following step 6.

    1. Navigate to the <API-M_HOME>/repository/resources/api_templates/default_api_template.xml file in the Publisher node.

    2. Add the following handler to the top of the set of handlers defined inside <handlers> config.

      Code Block
      <handler class="org.wso2.carbon.apimgt.gateway.handlers.common.MutualSSLCertificateHandler"/>


      A sample default_api_template.xml file with the above would look like below.

      Code Block
      <api xmlns="http://ws.apache.org/ns/synapse" name="$!apiName" context="$!apiContext" transports="$!transport">
        ...
        <handlers>
            
    <Password>wso2carbon</Password>
    1. <handler class="org.wso2.carbon.apimgt.gateway.handlers.common.MutualSSLCertificateHandler"/>
            
    </TrustStore>
    1. <handler class="org.wso2.carbon.apimgt.gateway.handlers.common.SynapsePropertiesHandler"/>
            
    <SSLVerifyClient>optional</SSLVerifyClient> </profile> </parameter>
    Note

    The  <API-M_HOME>/repository/resources/security directory can be changed according to the file path you have configured in Step 2.

    Open the <API-M_HOME>/repository/conf/api-manager.xml file. Set the  EnableMTLSForAPIs parameter to true.
    Code Block
    <APIManager>
    	...
      <EnableMTLSForAPIs>true</EnableMTLSForAPIs>
  6. Restart the server.

Create an API secured with Mutual SSL

...

Select Mutual SSL under API Security.
Image Removed

...

You can select both OAuth2 and Mutual SSL options. This means that the user can access the API using a valid OAuth2 token or using a valid client certificate. When OAuth2 and Mutual SSL are both enabled, Mutual SSL authentication will have a higher priority than OAuth2 as explained as follows:

...

OAuth2
token

...

Mutual SSL
Certificate

...

  • Initially, the Mutual SSL certificate is validated. If the validation is successful, the OAuth2 token is ignored.
  • If the Mutual SSL certificate fails, the OAuth2 token is validated, but if the OAuth2 token fails as well, the API call will fail.

...

  • The Mutual SSL certificate is validated. If the validation fails, the API call will fail.

...

  • The OAuth2 token is validated. If the validation fails, the API call will fail.

...

Info

After configuring, the certificate will be added to the Gateway nodes which are defined under the Environments in api-manager.xml. In a clustered setup, as gateway configurations are identical, sync the <API-M_HOME>/repository/resources/security/listenerprofiles.xml and <API-M_HOME>/repository/resources/security/client-truststore.jks among the gateway nodes. After the configured interval, the synapse transport will be reloaded in all the gateway nodes.

...

Invoke an API secured with Mutual SSL from the API Store

Note
titleBefore you begin...

Add the relevant certificate to your browser according to your private certificate.

  1. Invoke an API from the API Store.
  2. When you click Execute the browser will send a prompt similar to the one shown below. Select the corresponding certificate for the API.
    Image Removed

Limitations

Listed below are the known limitations for this feature.

...

Application subscription is not permitted for APIs that are only protected with Mutual SSL. Hence, subscription/application level throttling is not applicable for these type of APIs.

...

Resource level throttling is not applicable for the APIs that are only protected with Mutual SSL.

...

Resource level security will not be applicable for the APIs that are only protected with Mutual SSL.

...

    1. <handler class="org.wso2.carbon.apimgt.gateway.handlers.security.CORSRequestHandler">
               <property name="apiImplementationType" value="ENDPOINT"/>
            </handler>
        </handlers>
  1. Save and Publish the API


Invoke an API secured with Mutual SSL from the API Store

Note
titleBefore you begin...

Add the relevant certificate to your browser according to your private certificate.

  1. Invoke an API from the API Store.
  2. When you click Execute the browser will send a prompt similar to the one shown below. Select the corresponding certificate for the API.
    Image Added

Differences compared to APIs secured over OAuth 2.0

Listed below are the known differences in features when APIs are secured using Mutual SSL compared to OAuth 2.0.

  • Comparative to subscription level rate limiting policies, with Mutual SSL what you get is rate limiting policies by certificate. API developers can define the rate limit to be applied by each accepted certificate.

  • In the case of Mutual SSL since there are no access tokens involved, the concept of resource security "type" for API resources doesn't apply. Security "type" in API resources are based on whether the access token belongs to an application or an end-user. In the case of Mutual SSL the certificate is issued to the client application.

  • Fine grained authorization has to be done using message mediation policies. Since mutual TLS does not have a concept similar to that of OAuth 2.0 scopes, features such as role-based-access-control for example would need to be achieve using alternatives similar to message mediation policies.


Warning

The following is available only as a  WUM update and is effective from 15th July 2020 (2020-07-15). For more information on updating WSO2 API Manager, see Updating WSO2 API Manager.

Handling MTLS when SSL is terminated by the load balancer/reverse proxy

When SSL Termination of API requests happens at the load balancer/reverse proxy, the following prerequisites need to be met from the load balancer.

The below diagram shows how MutualSSL works in such an environment.

Image Added

By default, the WSO2 API Manager retrieves the client certificate from the X-WSO2-CLIENT-CERTIFICATE HTTP header. In order to change the header,

  1. Navigate to the <API-M_HOME>/repository/conf/api-manager.xml file in Gateway node.

  2. Put the following under <APIManager> section.

    Code Block
    <APIManager>
    	...
       <MutualSSL> 
           <ClientCertificateHeader>X-WSO2-CLIENT-CERTIFICATE</ClientCertificateHeader> 
           <!-- This property need to be true if MutualSSL connection established between load balancer and gateway.--> 
          <EnableClientCertificateValidation>false</EnableClientCertificateValidation> 
       </MutualSSL>
  3. Restart the API Manager.


Note

By default for Mutual SSL feature in Gateway, the WSO2 API Manager reload the new certificates from truststore into memory within an interval of 10mins. In order to change the reload interval,

  1. Navigate to the <API-M_HOME>/repository/conf/api-manager.xml file in Gateway node.
  2. Put the following under <APIManager> section. Add the reload interval in seconds inside <Period> configuration.

    Code Block
    <APIManager>
    	...
        <CertificateReLoaderConfiguration>
           <Period>10</Period>
        </CertificateReLoaderConfiguration>
  3. Restart the API Manager.