Friday, December 1, 2017

Azure Container Instance (2): Introducing ACI Secret Volumes

A new type of volume named secret volume was supported in Azure Container Instance since version 2017-12-01-preview.

What is secret volume?

A secret volume is used to pass sensitive information, such as passwords and certificates, to container groups. You can store secrets and mount them as files for use by containers.

How to use secret volume?

First a secret object is added into the volumes array of the container group, and then the volume mount is added into the volumeMounts of a container. The name of the volume mount should match the name of the volume.

The following is an ARM template of a container group with a secret volume:

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "containergroupname": {
      "type": "string",
      "metadata": {
        "description": "Name for the container group"
      }
    },
    "containername": {
      "type": "string",
      "metadata": {
        "description": "Name for the container"
      }
    },
    "volumename": {
      "type": "string",
      "metadata": {
        "description": "Name for the secret volume"
      }
    },
    "clientCertificate": {
      "metadata": {
        "description": "The base64 client certificate used to communicate with the master"
      },
      "type": "string"
    },
    "clientPrivateKey": {
      "metadata": {
        "description": "The base64 client private key used to communicate with the master"
      },
      "type": "securestring"
    },
    "port": {
      "type": "string",
      "metadata": {
        "description": "Port to open on the container and the public IP address."
      },
      "defaultValue": "80"
    },
    "cpuCores": {
      "type": "string",
      "metadata": {
        "description": "The number of CPU cores to allocate to the container."
      },
      "defaultValue": "1.0"
    },
    "memoryInGb": {
      "type": "string",
      "metadata": {
        "description": "The amount of memory to allocate to the container in gigabytes."
      },
      "defaultValue": "1.5"
    }
  },
  "variables": {},
  "resources": [
    {
      "name": "[parameters('containergroupname')]",
      "type": "Microsoft.ContainerInstance/containerGroups",
      "apiVersion": "2017-12-01-preview",
      "location": "[resourceGroup().location]",
      "dependsOn": [],
      "properties": {
        "containers": [
          {
            "name": "[parameters('containername')]",
            "properties": {
              "command": [
                "bin/bash",
                "-c",
                "cp /mnt/secrets/clientCertificate /mnt/azurefile && cp /mnt/secrets/clientPrivateKey /mnt/azurefile && while sleep 50000; do echo sleep; done"
              ],
              "image": "nginx",
              "ports": [
                {
                  "port": "[parameters('port')]"
                }
              ],
              "resources": {
                "requests": {
                  "cpu": "[parameters('cpuCores')]",
                  "memoryInGb": "[parameters('memoryInGb')]"
                }
              },
              "volumeMounts": [
                {
                  "name": "[parameters('volumename')]",
                  "mountPath": "/mnt/secrets",
                  "readOnly": false
                },
                {
                  "name": "azurefile",
                  "mountPath": "/mnt/azurefile",
                  "readOnly": false
                }
              ]
            }
          }
        ],
        "osType": "Linux",
        "ipAddress": {
          "type": "Public",
          "ports": [
            {
              "protocol": "tcp",
              "port": "[parameters('port')]"
            }
          ]
        },
        "volumes": [
          {
            "name": "[parameters('volumename')]",
            "secret": {
              "clientCertificate": "[parameters('clientCertificate')]",
              "clientPrivateKey": "[parameters('clientPrivateKey')]"
            }
          },
          {
            "name": "azurefile",
            "azureFile": {
              "shareName": "<YourAzureFileShare>",
              "storageAccountName": "<YourAzureStorageAccountName>",
              "storageAccountKey": "<YourAzureStorageAccountKey>"
            }
          }
        ]
      }
    }
  ],
  "outputs": {
    "containerIPv4Address": {
      "type": "string",
      "value": "[reference(resourceId('Microsoft.ContainerInstance/containerGroups/', parameters('containergroupname'))).ipAddress.ip]"
    }
  }
}

And the parameters of template look like:

{
  "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "containergroupname": {
      "value": "GEN-UNIQUE"
    },
    "containername": {
      "value": "GEN-UNIQUE"
    },
    "volumename": {
      "value": "GEN-UNIQUE"
    },
    "clientCertificate": {
      "reference": {
        "keyVault": {
          "id": "GEN-KEYVAULT-RESOURCE-ID"
        },
        "secretName": "GEN-KEYVAULT-SSL-SECRET-NAME"
      }
    },
    "clientPrivateKey": {
      "reference": {
        "keyVault": {
          "id": "GEN-KEYVAULT-RESOURCE-ID"
        },
        "secretName": "GEN-KEYVAULT-SSL-SECRET-NAME"
      }
    }
  }
}

The secret in the sample above has two set of key-value pairs, one for client certificate and the other for client private key. The certificate and private key are originally in Azure key vault. The certificate is mounted as a file /mnt/secrets/clientCertificate in the container, and the private key is mounted as a file /mnt/secrets/clientPrivateKey.

In the sample, the two files for the certificate and key are copied to Azure file share, so we can see them in Azure portal. In the real development scenarios, we can do anything we like with the certificate and private key, such as setting SSL connections. 

No comments:

Post a Comment

AKS (1) - Five seconds latency when resolving DNS

We intermittently meet 5s latencies in an AKS clusters with CNI when it’s resolving DNS. This article is to summarize what we have learned...