Installing Crypto Express Network API for Secure Execution Enclaves

Before you install Crypto Express Network API for Secure Execution Enclaves, ensure that you complete the prerequisites and download the image.

Installing Crypto Express Network API for Secure Execution Enclaves image

For detailed installation instructions, see "Chapter 13 - Installing a new software appliance in a Secure Service Container partition" in the Secure Service Container User's Guide, SC28-6978-02a.

Switching to the Installer

After you complete installing the Crypto Express Network API for Secure Execution Enclaves image, access to the console UI is disabled. Before you reinstall the image, you must switch the system to the installer mode. You can perform one of the following two methods to switch to the installer.

1. Switch to the Installer on the Hardware Management Console (HMC)

Select Secure Service Container Installer as the boot option after you log in to the HMC. For more information, see "Chapter 4. Starting a Secure Service Container partition on a standard mode system" from the Secure Service Container User's Guide, SC28-6978-02a.

2. Using REST API to switch to the installer

The REST API can be used to switch to the installer under the following conditions:

  • The caller must provide an API token.

  • The user represented by the API token must have an "administrator" role.

    POST /api/com.ibm.zaci.system/maintenance-actions/switch-to-installer
    

You can use the following sample shell script as a reference for using the Rest API

  • Appliance IP, administrator's user and password are required
  • jq json parsing tool is required to installed
#!/bin/bash -e

appliance_ip=""
admin_user=""
admin_pass=""

get_access_token() {
    echo "Get access token"
    echo "---> request: /api/com.ibm.zaci.system/api-tokens"
    req_json=$(cat << EOF
{
   "kind": "request",
   "parameters":{
      "user":"${admin_user}",
      "password":"${admin_pass}"
   }
}
EOF
)

    auth_token=$(curl -k -X POST https://${appliance_ip}/api/com.ibm.zaci.system/api-tokens -H 'zACI-API: com.ibm.zaci.system/1.0' -H 'Content-type: application/vnd.ibm.zaci.payload+json;version=1.0' -H 'Accept: application/vnd.ibm.zaci.payload+json' -d "${req_json}" | jq -r .parameters.token)
    echo "---> auth_token: [${auth_token}]"
}

switch_to_installer(){
    echo "switch to installer mode"
    echo "---> request: /api/com.ibm.zaci.system/maintenance-actions/switch-to-installer"

    response=$(curl -k -X POST https://${appliance_ip}/api/com.ibm.zaci.system/maintenance-actions/switch-to-installer  -H 'zACI-API: com.ibm.zaci.system/1.0' -H 'Content-type: application/vnd.ibm.zaci.payload+json; charset=UTF-8;version=1.0' -H 'Accept: application/vnd.ibm.zaci.payload+json' -H "Authorization: Bearer ${auth_token}")
    echo "---> response: [${response}]"
}

force_appliance_to_installer(){
    echo "Force appliance to installer mode"
    echo "---> request: /api/com.ibm.zaci.system/appliance"

    response=$(curl -k -X GET https://${appliance_ip}/api/com.ibm.zaci.system/appliance -H 'zACI-API: com.ibm.zaci.system/1.0' -H 'Content-type: application/vnd.ibm.zaci.payload+json;version=1.0' -H 'Accept: application/vnd.ibm.zaci.payload+json' -H "Authorization: Bearer ${auth_token}" | jq -r .properties.name)
    echo "---> response: [${response}]"
    if [ "${response}" = "Secure Service Container Installer" ]; then
       echo "Appliance is already in installer mode"
    else
       echo "Appliance is not in installer mode"
       switch_to_installer
    fi
}

get_access_token
force_appliance_to_installer

3. Sample installation script

The following shell script can be used as a sample script to install the appliance. Before you run the installation script, the parameters listed at the beginning of the script must be defined as shown in the sample:

#!/bin/bash

# the ip-address of the appliance
appliance_ip="1.1.2.1"
# the user of the appliance
admin_user="root"
# the password of the appliance
admin_pass="password"
# the disktype (DASD or FCP), default is DASD
appliance_disktype="DASD"
# the path of the crypto-appliance image
apppliance_image="./crypto-appliance-rel.img.gz"

echo "appliance_ip: ${appliance_ip}"
echo "appliance_disktype: ${appliance_disktype}"
echo "apppliance_image: ${apppliance_image}"

wait_for_lpar() {
   echo "wait for lpar ready..."
   max_tries=81
   index=1 ; while [[ $index -le $max_tries ]] ; do
      ((index = index + 1)) ;
      req_json=$(cat << EOF
{
   "kind": "request",
   "parameters":{
      "user":"${admin_user}",
      "password":"${admin_pass}"
   }
}
EOF
)
      response=$(curl -k -X POST https://${appliance_ip}/api/com.ibm.zaci.system/api-tokens -H 'zACI-API: com.ibm.zaci.system/1.0' -H 'Content-type: application/vnd.ibm.zaci.payload+json;version=1.0' -H 'Accept: application/vnd.ibm.zaci.payload+json' -d "${req_json}")
      if [[ $? -eq 0 ]]; then
         if jq -e . >/dev/null 2>&1 <<<"$response"; then
            kind=$(echo "$response" | jq -r .kind)
            auth_token=$(echo "$response" | jq -r .parameters.token)
            if [ "${kind}" = "response" ]; then
               echo "---> auth_token: [${auth_token}]"
               echo "lpar is ready."
               return 0
            fi;
         fi
      fi
      echo "response:$response"
      echo "lpar is not ready, continue try [$index]..."
      sleep 10s
    done
    echo "waiting for lpar ready timeout."
    exit 1
}

force_to_accept_license(){
   echo "Get current license status"

   echo "---> request: /api/com.ibm.zaci.system/software-license"
   response=$(curl -k -X GET "https://${appliance_ip}/api/com.ibm.zaci.system/software-license" -H 'zACI-API: com.ibm.zaci.system/1.0' -H 'Content-type: application/vnd.ibm.zaci.payload+json;version=1.0' -H 'Accept: application/vnd.ibm.zaci.payload+json;version=1.0' -H "Authorization: Bearer ${auth_token}")
   echo "---> response: [${response}]"

   license_status=$(echo "${response}" | jq .properties.accepted)
   if [ "${license_status}" = "false" ]; then
      echo "Force to accept license status"
req_json=$(cat << EOF
{
   "kind": "request",
   "parameters":{
      "accept": true
   }
}
EOF
)
      response=$(curl -k -X PUT https://${appliance_ip}/api/com.ibm.zaci.system/software-license -H 'zACI-API: com.ibm.zaci.system/1.0' -H 'Content-type: application/vnd.ibm.zaci.payload+json;version=1.0' -H 'Accept: application/vnd.ibm.zaci.payload+json' -H "Authorization: Bearer ${auth_token}" -d "${req_json}" | jq -r .)
      echo "---> response: [${response}]"
   else
      echo "License is already accept"
   fi;
}

switch_to_installer(){
    echo "switch to installer mode"
    echo "---> request: /api/com.ibm.zaci.system/maintenance-actions/switch-to-installer"

    response=$(curl -k -X POST https://${appliance_ip}/api/com.ibm.zaci.system/maintenance-actions/switch-to-installer  -H 'zACI-API: com.ibm.zaci.system/1.0' -H 'Content-type: application/vnd.ibm.zaci.payload+json; charset=UTF-8;version=1.0' -H 'Accept: application/vnd.ibm.zaci.payload+json' -H "Authorization: Bearer ${auth_token}")
    echo "---> response: [${response}]"
}

force_appliance_to_installer(){
    echo "Force appliance to installer mode"
    echo "---> request: /api/com.ibm.zaci.system/appliance"

    response=$(curl -k -X GET https://${appliance_ip}/api/com.ibm.zaci.system/appliance -H 'zACI-API: com.ibm.zaci.system/1.0' -H 'Content-type: application/vnd.ibm.zaci.payload+json;version=1.0' -H 'Accept: application/vnd.ibm.zaci.payload+json' -H "Authorization: Bearer ${auth_token}" | jq -r .properties.name)
    echo "---> response: [${response}]"
    if [ "${response}" = "Secure Service Container Installer" ]; then
       echo "Appliance is already in installer mode"
    else
       echo "Appliance is not in installer mode"
       force_to_accept_license
       switch_to_installer
       wait_for_lpar
    fi
}

get_free_storage_dasd(){
   echo "---> request: /api/com.ibm.zaci.system/storage-devices?type=ECKD&status=free"
   response=$(curl -k -X GET "https://${appliance_ip}/api/com.ibm.zaci.system/storage-devices?type=ECKD&status=free" -H 'zACI-API: com.ibm.zaci.system/1.0' -H 'Content-type: application/vnd.ibm.zaci.payload+json;version=1.0' -H 'Accept: application/vnd.ibm.zaci.payload+json;version=1.0' -H "Authorization: Bearer ${auth_token}" | jq .)
   DASD_ID=`echo $response | jq -r '.instances|.[0].id'`
   echo "DASD_ID=$DASD_ID"
}

get_free_storage_fcp(){
   echo "---> request:https://${appliance_ip}/api/com.ibm.zaci.system/fcp-disks?type=FCP&status=free"
   response=$(curl -k -X GET "https://${appliance_ip}/api/com.ibm.zaci.system/fcp-disks?type=FCP&status=free" -H 'zACI-API: com.ibm.zaci.system/1.0' -H 'Content-type: application/vnd.ibm.zaci.payload+json;version=1.0' -H 'Accept: application/vnd.ibm.zaci.payload+json;version=1.0' -H "Authorization: Bearer ${auth_token}" | jq .)
   FCP_DEVICE=`echo $response | jq -r '.instances|.[0].paths|.[0]."fcp-device"'`
   FCP_WWPN=`echo $response | jq -r '.instances|.[0].paths|.[0]."target"'`
   FCP_LUN=`echo $response | jq -r '.instances|.[0].paths|.[0]."lun"'`
   echo "FCP_DEVICE=$FCP_DEVICE"
   echo "FCP_WWPN=$FCP_WWPN"
   echo "FCP_LUN=$FCP_LUN"
   echo "id=${FCP_DEVICE} wwpn=${FCP_WWPN} lun=${FCP_LUN}"
}

reboot_dasd(){
   DASD_ID=$1

   echo "reboot dasd"
   echo "---> request: /api/com.ibm.zaci.system/sw-appliances/select:"
   req_json=$(cat << EOF
{
   "kind": "request",
   "parameters":{
      "disk": {
         "id": "$DASD_ID"
      },
      "reboot-after": true
   }
}
EOF
)

   response=$(curl -k -X PUT https://${appliance_ip}/api/com.ibm.zaci.system/sw-appliances/select -H 'zACI-API: com.ibm.zaci.system/1.0' -H 'Content-type: application/vnd.ibm.zaci.payload+json;version=1.0' -H 'Accept: application/vnd.ibm.zaci.payload+json' -H "Authorization: Bearer ${auth_token}" -d "${req_json}")
   echo "---> response: [${response}]"
}

reboot_fcp(){
   FCP_DEVICE=$1
   FCP_WWPN=$2
   FCP_LUN=$3

   echo "reboot fcp"
   echo "---> request: /api/com.ibm.zaci.system/sw-appliances/select:"
   req_json=$(cat << EOF
{
   "kind": "request",
   "parameters":{
      "disk": {
         "id": "$FCP_DEVICE",
         "wwpn": "$FCP_WWPN",
         "lun": "$FCP_LUN"
      },
      "reboot-after": true
   }
}
EOF
)

   response=$(curl -k -X PUT https://${appliance_ip}/api/com.ibm.zaci.system/sw-appliances/select -H 'zACI-API: com.ibm.zaci.system/1.0' -H 'Content-type: application/vnd.ibm.zaci.payload+json;version=1.0' -H 'Accept: application/vnd.ibm.zaci.payload+json' -H "Authorization: Bearer ${auth_token}" -d "${req_json}")
   echo "---> response: [${response}]"
}

upload_image_dasd(){
   DASD_ID=$1

   echo "upload image with storage type: dasd"
   echo "---> request: /api/com.ibm.zaci.system/sw-appliances/install?id=${DASD_ID}"

   echo "DASD_ID=$DASD_ID"
   echo "auth_token=${auth_token}"
   FILE_SIZE=$(ls -l "${apppliance_image}" | awk '{print $5}')
   echo "file size=$FILE_SIZE"

   response=$(curl -k -X POST "https://${appliance_ip}/api/com.ibm.zaci.system/sw-appliances/install?id=${DASD_ID}"  -H 'zACI-API: com.ibm.zaci.system/1.0' -H 'Content-type: application/octet-stream' -H 'Accept: application/vnd.ibm.zaci.payload+json' -H "Content-length: $FILE_SIZE" -H "Authorization: Bearer ${auth_token}" -T "${apppliance_image}")
   echo "---> response: [${response}]"
}

upload_image_fcp(){
   FCP_DEVICE=$1
   FCP_WWPN=$2
   FCP_LUN=$3
   echo "upload image with storage type: fcp"
   echo "---> request: /api/com.ibm.zaci.system/sw-appliances/install?id=${FCP_DEVICE}&wwpn=${FCP_WWPN}&lun=${FCP_LUN}"

   FILE_SIZE=$(ls -l "${apppliance_image}" | awk '{print $5}')

   echo "file size=$FILE_SIZE"

   response=$(curl -k -X POST "https://${appliance_ip}/api/com.ibm.zaci.system/sw-appliances/install?id=${FCP_DEVICE}&wwpn=${FCP_WWPN}&lun=${FCP_LUN}"  -H 'zACI-API: com.ibm.zaci.system/1.0' -H 'Content-type: application/octet-stream' -H 'Accept: application/vnd.ibm.zaci.payload+json' -H "Content-length: $FILE_SIZE" -H "Authorization: Bearer ${auth_token}" -T "${apppliance_image}")
   echo "---> response: [${response}]"
}

upload_image(){
   if [ "$appliance_disktype" = "FCP" ]; then
      get_free_storage_fcp
      upload_image_fcp $FCP_DEVICE $FCP_WWPN $FCP_LUN
      reboot_fcp $FCP_DEVICE $FCP_WWPN $FCP_LUN
   else
      get_free_storage_dash
      upload_image_dasd $DASD_ID
      reboot_dasd $DASD_ID
   fi
}

wait_for_lpar
force_appliance_to_installer
upload_image
wait_for_lpar

Note: If you already installed Crypto Express Network API for Secure Execution Enclaves version 1.1.0, you can reinstall with version 1.1.1 following the same installation instructions.

Checking the installation status

As the console UI of the installed appliance is disabled, you can use one of the following methods to check the installation status:

1. Check the status on the Hardware Management Console (HMC)

After logon the HMC, you can found the specific LPAR, related to which a new installed version can be viewed in the table

2. Using REST API to check the status

To execute below sample shell script, if the responded "properties.name" is "IBM Hyper Protect Crypto Appliance" and there is the expected version in "properties.version", the appliance is installed successfully

#!/bin/bash -e
appliance_ip=""
admin_user=""
admin_pass=""
get_access_token() {
    echo "Get access token"
    req_json=$(cat << EOF
{
   "kind": "request",
   "parameters":{
      "user":"${admin_user}",
      "password":"${admin_pass}"
   }
}
EOF
)
    auth_token=$(curl -k -X POST https://${appliance_ip}/api/com.ibm.zaci.system/api-tokens -H 'zACI-API: com.ibm.zaci.system/1.0' -H 'Content-type: application/vnd.ibm.zaci.payload+json;version=1.0' -H 'Accept: application/vnd.ibm.zaci.payload+json' -d "${req_json}" | jq -r .parameters.token)
}
get_appliance_status(){
    echo "---> request: /api/com.ibm.zaci.system/appliance"
    response=$(curl -k -X GET https://${appliance_ip}/api/com.ibm.zaci.system/appliance -H 'zACI-API: com.ibm.zaci.system/1.0' -H 'Content-type: application/vnd.ibm.zaci.payload+json;version=1.0' -H 'Accept: application/vnd.ibm.zaci.payload+json' -H "Authorization: Bearer ${auth_token}" | jq -r .)
    echo "---> appliance: [${response}]"
}
get_access_token
get_appliance_status

The sample json response:

{
  "kind": "instance",
  "self": "/api/com.ibm.zaci.system/appliance",
  "resource-name": "appliance",
  "resource-version": "1.0",
  "properties": {
    "self": "/api/com.ibm.zaci.system/appliance",
    "name": "IBM Hyper Protect Crypto Appliance",
    "description": "IBM Hyper Protect Crypto Appliance",
    "version": "23.3.2",
    "boot-time": 1678437000,
    "hostname": "hursscc.hursley.ibm.com",
    "physical-server-name": "IYACPCTX",
    "virtual-server-name": "HURSSCC"
  }
}

Preparing Rsyslog server for log collection

Rsyslog is a log processing system that can be configured to receive logs from the c16 server and output the logs for your review. It is installed by default on Ubuntu.

  1. Install rsyslog-gnutls to enable TLS log transaction. For example, for Ubuntu:

    apt-get install -y rsyslog-gnutls
    
  2. Prepare a TLS keypair for the Rsyslog central server by completing the following steps:

    • The following certificates must be prepared in this section:

      Filename Description
      rsyslog-ca.pem ROOT certificate of Rsyslog server
      rsyslog-cert.pem Rsyslog central server certificate
      rsyslog-server.key Rsyslog central server key
      rsyslog-client.pem Rsyslog client certificate which is configured into crypto appliance by API
      rsyslog-client.key Rsyslog client key which is configured into crypto appliance by API

      Follow Creating OpenSSL certificates for Crypto Express Network API for Secure Execution Enclaves, to prepare the required TLS certificate by using OpenSSL(self-signed certificates):

    • Replace %prefix% with rsyslog

      Note: If you want to use other methods of preparing Rsyslog certificates, follow these instructions.

  3. Follow the instructions in Encrypting Syslog Traffic with TLS (SSL). Ensure that you read the documentation that matches the version of your Rsyslog server. Choose one of the following methods for configuring the rsyslog.conf file:

    1. An example of settings in the Rsyslog configuration file rsyslog.conf, which is usually located under /etc/:

      global(
      DefaultNetstreamDriver="gtls"
      DefaultNetstreamDriverCAFile="/root/rsyslog-ca.pem"
      DefaultNetstreamDriverCertFile="/root/rsyslog-cert.pem"
      DefaultNetstreamDriverKeyFile="/root/rsyslog-server.key"
      )
      module(load="imtcp" StreamDriver.Name="gtls" StreamDriver.Mode="1" gnutlsprioritystring="SECURE128:-VERS-TLS-ALL:+VERS-TLS1.2" StreamDriver.Authmode="x509/certvalid")
      input(type="imtcp"
         port="6514"
         ruleset="to_local")
      
      module(load="builtin:omfile")
      ruleset(name="to_local"){
         action(type="omfile" dirCreateMode="0766" FileCreateMode="0644" File="/root/c16server.log")
      }
      
    2. If you want to use the same Rsyslog server that you have set up to use with the Hyper Protect Container Runtime instance, use the following example of the configuration of a Rsyslog server:

      # make gtls driver the default and set certificate files
      $DefaultNetstreamDriver "gtls"
      $DefaultNetstreamDriverCAFile /root/rsyslog-ca.pem
      $DefaultNetstreamDriverCertFile /root/rsyslog-cert.pem
      $DefaultNetstreamDriverKeyFile /root/rsyslog-server.key
      # provides TCP syslog reception
      module(load="imtcp"
              StreamDriver.Name="gtls"
              StreamDriver.Mode= "1"
              StreamDriver.Authmode="x509/certvalid" 
      )
      input(type="imtcp" port="6514")
      # Template for incoming logs
      $template incoming-remote-logs,"/var/log/remotelogs/%FROMHOST-IP%/%PROGRAMNAME%.log"
      *.* ?incoming-remote-logs
      

      Ensure that you create the root path to store the received traces from clients by using the mkdir -p /var/log/remotelogs command. Traces that are received from each client can be found in the specific %FROMHOST-IP% folder under the path "/var/log/remotelogs".

  4. After you finish the configurations, restart the Rsyslog server.

    systemctl restart rsyslog.service
    

Now you are ready to configure the Crypto Express Network API for Secure Execution Enclaves and collect and send logs to the Rsyslog central server.

Notes:

  • It is recommended to use the same Rsyslog version (current version is 8.2001.0-1ubuntu1.3). If you choose to use a different version, confirm the steps on the Rsyslog server official website.
  • During log server downtime, the first log message is lost due to plain TCP connection.
  • By default, the 'authmode' of Rsyslog peer (listener) is 'x509/certvalid' in Crypto Express Network API for Secure Execution Enclaves appliance, and identity authentication is required.