# Creating an ACME resolver webhook for responses to DNS01 challenges


Install the [cert-manager](https://cert-manager.io/docs/) application with the DNS01 webhook resolver to automatically pass [domain ownership](../../certificate-manager/concepts/challenges.md) checks for domains registered in Yandex Cloud DNS.

To run a webhook in a Managed Service for Kubernetes cluster:

1. [Set up the Managed Service for Kubernetes cluster](#before-managed-kubernetes).
1. [Install and run a webhook in a Managed Service for Kubernetes cluster](#yandex-webhook).
1. [Test the webhook](#check-yandex-webhook).
1. [Delete the resources you created](#clear-out).

{% note info %}

The certificate manager with the ACME webhook for Yandex Cloud DNS supports [Wildcard certificates](https://en.wikipedia.org/wiki/Public_key_certificate#Wildcard_certificate).

{% endnote %}

## Getting started {#before-you-begin}

Sign up for Yandex Cloud and create a [billing account](../../billing/concepts/billing-account.md):
1. Navigate to the [management console](https://console.yandex.cloud) and log in to Yandex Cloud or create a new account.
1. On the **[Yandex Cloud Billing](https://center.yandex.cloud/billing/accounts)** page, make sure you have a billing account linked and it has the `ACTIVE` or `TRIAL_ACTIVE` [status](../../billing/concepts/billing-account-statuses.md). If you do not have a billing account, [create one](../../billing/quickstart/index.md) and [link](../../billing/operations/pin-cloud.md) a cloud to it.

If you have an active billing account, you can create or select a [folder](../../resource-manager/concepts/resources-hierarchy.md#folder) for your infrastructure on the [cloud page](https://console.yandex.cloud/cloud).

[Learn more about clouds and folders here](../../resource-manager/concepts/resources-hierarchy.md).


### Required paid resources {#paid-resources}

The support cost for this solution includes:

* Fee for using the master and outgoing traffic in a Managed Service for Kubernetes cluster (see [Managed Service for Kubernetes pricing](../../managed-kubernetes/pricing.md)).
* Fee for using computing resources, OS, and storage in cluster nodes (VMs) (see [Compute Cloud pricing](../../compute/pricing.md)).
* Fee for a public IP address for the cluster nodes (see [Virtual Private Cloud pricing](../../vpc/pricing.md#prices-public-ip)).


## Set up your environment {#prepare-environment}

1. If you do not have the Yandex Cloud CLI yet, [install and initialize it](../../cli/quickstart.md#install).
1. Install [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/), which is the command line interface for Kubernetes.
1. Make sure you have enough [resources available in the cloud](../../resource-manager/concepts/limits.md).
1. If you do not have a [network](../../vpc/concepts/network.md#network) yet, [create one](../../vpc/operations/network-create.md).
1. If you do not have any [subnets](../../vpc/concepts/network.md#subnet) yet, [create them](../../vpc/operations/subnet-create.md) in the [availability zones](../../overview/concepts/geo-scope.md) where the new Managed Service for Kubernetes cluster and node group will reside.
1. [Create these service accounts](../../iam/operations/sa/create.md):

   * `sa-kubernetes` with the following [roles](../../managed-kubernetes/security/index.md#yc-api):

     * `k8s.clusters.agent` and `vpc.publicAdmin` for the folder where you will create the Managed Service for Kubernetes cluster.
     * `container-registry.images.puller` for the folder containing a Docker image [registry](../../container-registry/concepts/registry.md).

     This service account will be used to create the resources your cluster needs, and Managed Service for Kubernetes nodes will pull the required [Docker images](../../container-registry/concepts/docker-image.md) from the registry.

   * `sa-dns-editor` with the `dns.editor` role for the folder containing the [public zone](../../dns/concepts/dns-zone.md#public-zones). This service account will be used to create DNS [resource records](../../dns/concepts/resource-record.md).

1. [Create security groups](../../managed-kubernetes/operations/connect/security-groups.md) for the Managed Service for Kubernetes cluster and its node groups.

    {% note warning %}
    
    The configuration of security groups determines performance and availability of the cluster and the services and applications running in it.
    
    {% endnote %}

1. [Add](../../vpc/operations/security-group-add-rule.md) the following rules to your security groups:
   
     * Add to the [cluster security group](../../managed-kubernetes/operations/connect/security-groups.md#rules-master) an outbound traffic rule allowing certificate checks via a cert-manager webhook:
       * **Port range**: `10250`.
       * **Protocol**: `TCP`.
       * **Destination name**: `CIDR`.
       * **CIDR blocks**: `0.0.0.0/0`.
     * Add to the [node group security group](../../managed-kubernetes/operations/connect/security-groups.md#rules-internal-nodegroup) an outbound traffic rule allowing connection to Let's Encrypt® servers for certificates:
       * **Port range**: `443`.
       * **Protocol**: `TCP`.
       * **Destination name**: `CIDR`.
       * **CIDR blocks**: `0.0.0.0/0`.

## Prepare your Managed Service for Kubernetes cluster {#before-managed-kubernetes}

### Create a Managed Service for Kubernetes cluster {#kubernetes-cluster-create}

{% list tabs group=instructions %}

- Management console {#console}

  1. In the [management console](https://console.yandex.cloud), select the folder where you want to create a Managed Service for Kubernetes cluster.
  1. Navigate to **Managed Service for&nbsp;Kubernetes**.
  1. Click **Create cluster**.
  1. Enter the name for the cluster: `kubernetes-cluster-wh`.
  1. **Service account for resources**: Specify the `sa-kubernetes` service account that will be used to create resources.
  1. **Service account for nodes**: Specify the `sa-kubernetes` service account the Managed Service for Kubernetes nodes will use to access the Docker image registry.
  1. Specify the [release channel](../../managed-kubernetes/concepts/release-channels-and-updates.md). You will not be able to edit this setting once you create the Managed Service for Kubernetes cluster.
  1. Under **Master configuration**:
     * **Kubernetes version**: Select the Kubernetes version to install on the [Managed Service for Kubernetes master](../../managed-kubernetes/concepts/index.md#master). It must match the Kubernetes command line version.
     * **Public address**: Select the [IP address](../../vpc/concepts/address.md) assignment method:
       * `Auto`: Assign a random IP address from the Yandex Cloud IP address pool.
     * **Type of master**: Select the master type:
       * `Basic`: To create a single master host in the selected availability zone. Specify the cloud network and select the subnet for the master host.
       * `Highly available`: To create a single master host in each availability zone. Specify the cloud network and subnet for each availability zone.
     * Select [security groups](../../managed-kubernetes/operations/connect/security-groups.md) for the Managed Service for Kubernetes cluster's network traffic.
  1. Under **Cluster network settings**:
     * **CIDR cluster**: Specify the IP address range to allocate addresses to [pods](../../managed-kubernetes/concepts/index.md#pod) from.
     * **CIDR services**: Specify the IP address range to allocate IP addresses to [services](../../managed-kubernetes/concepts/index.md#service) from.
     * Set the subnet mask for the Managed Service for Kubernetes nodes and the maximum number of pods per node.
  1. Click **Create**.
  1. Wait until the cluster status switches to `Running` and its state, to `Healthy`.

{% endlist %}

### Add credentials to the kubectl configuration file {#add-conf}

{% list tabs group=instructions %}

- CLI {#cli}

  1. Run this command:

     ```bash
     yc managed-kubernetes cluster get-credentials kubernetes-cluster-wh --external
     ```

     By default, credentials are added to the `$HOME/.kube/config` directory. If you need to change the configuration location, use the `--kubeconfig <file_path>` parameter.

  1. Check the `kubectl` configuration after adding the credentials:

     ```bash
     kubectl config view
     ```

     Result:

     ```yml
     apiVersion: v1
     clusters:
       - cluster:
         certificate-authority-data: DATA+OMITTED
     ...
     ```

{% endlist %}

### Create a node group {#node-group-create}

{% list tabs group=instructions %}

- Management console {#console}

  1. In the [management console](https://console.yandex.cloud), select the folder where you created the required Managed Service for Kubernetes cluster.
  1. Navigate to **Managed Service for&nbsp;Kubernetes**.
  1. Select the `kubernetes-cluster-wh` cluster.
  1. On the cluster page, navigate to the ![nodes-management.svg](../../_assets/console-icons/graph-node.svg) **Node manager** tab.
  1. Click **Create a node group**.
  1. Enter a name and description for the Managed Service for Kubernetes node group.
  1. In the **Kubernetes version** field, select the Kubernetes version for the Managed Service for Kubernetes nodes.
  1. Under **Scaling**, select its type:
     * `Fixed`, to keep a fixed number of nodes in the Managed Service for Kubernetes group. Specify the number of nodes in the Managed Service for Kubernetes group.
     * `Automatic`, to manage the number of nodes in the Managed Service for Kubernetes group using [Managed Service for Kubernetes cluster autoscaling](../../managed-kubernetes/concepts/autoscale.md#ca).
  1. Under **Changes during creation and updates**, specify the maximum number of [VMs](../../compute/concepts/vm.md) by which you can exceed or reduce the Managed Service for Kubernetes group size.
  1. Under **Computing resources**:
     * Select a [platform](../../compute/concepts/vm-platforms.md).
     * Specify the required number of vCPUs, [guaranteed vCPU performance](../../compute/concepts/performance-levels.md), and the amount of RAM.

  1. Under **Storage**:
     * Specify the **Disk type** for the Managed Service for Kubernetes group nodes:
       * `HDD`: Standard network drive; HDD network block storage.
       * `SSD`: Fast network drive; SSD network block storage.
       * `Non-replicated SSD`: Network drive with enhanced performance achieved by eliminating redundancy. You can only change the size of this disk type in 93 GB increments.
       * `SSD IO`: Network drive with the same performance specifications as `Non-replicated SSD`, plus redundancy. You can only change the size of this disk type in 93 GB increments.

       For more information about disk types, see [this Yandex Compute Cloud guide](../../compute/concepts/disk.md#disks_types).
     * Specify the disk size for the Managed Service for Kubernetes group nodes.
  1. Under **Network settings**:
     * In the **Public address** field, select an IP address assignment method:
       * `Auto`: Assign a random IP address from the Yandex Cloud IP address pool.
     * Select [security groups](../../managed-kubernetes/operations/connect/security-groups.md).
     * Select the availability zone and subnet to place the Managed Service for Kubernetes group nodes in.
  1. Under **Access**, specify the access credentials for the Managed Service for Kubernetes group nodes over SSH:
     * **Login**: Enter the username.
     * **SSH key**: Paste the contents of the [public key](../../managed-kubernetes/operations/node-connect-ssh.md#creating-ssh-keys) file.
  1. Click **Create**.
  1. Wait until the node group status switches to `Running`.

{% endlist %}

## Install and run a webhook in a Managed Service for Kubernetes cluster {#yandex-webhook}

1. Clone the webhook repository with the certificate manager configured to issue Let's Encrypt certificates:

   ```bash
   git clone https://github.com/yandex-cloud/cert-manager-webhook-yandex.git
   ```

1. [Install Helm](https://helm.sh/docs/intro/install/) to manage packages in your Kubernetes cluster.
1. Install the webhook using Helm:

   ```bash
   helm install \
     --namespace cert-manager \
     --create-namespace \
     yandex-webhook ./cert-manager-webhook-yandex/deploy/cert-manager-webhook-yandex
   ```

1. Make sure the webhook is running:

   ```bash
   kubectl get pods -n cert-manager --watch
   ```

   Make sure the records contain the ACME webhook for Yandex Cloud DNS:

   ```text
   NAME                                                          READY   STATUS    RESTARTS   AGE
   ... 
   yandex-webhook-cert-manager-webhook-yandex-55********-tw4mq   1/1     Running   1          43m
   ```

## Test the webhook {#check-yandex-webhook}

### Prepare configuration files {#prepare-files}

1. Create an [authorized key](../../iam/concepts/authorization/key.md) for the `sa-dns-editor` service account and save it to the `iamkey.json` file:

   ```bash
   yc iam key create iamkey \
     --service-account-id=<service_account_ID> \
     --format=json \
     --output=iamkey.json
   ```

1. Create a secret with the service account key:

   ```bash
   kubectl create secret generic cert-manager-secret --from-file=iamkey.json -n cert-manager
   ```

1. Create the `cluster-issuer.yml` file with the `ClusterIssuer` object manifest that uses the DNS01 webhook resolver for the Cloud DNS domain:

   ```yml
   apiVersion: cert-manager.io/v1
   kind: ClusterIssuer
   metadata:
    name: clusterissuer
    namespace: default
   spec:
    acme:
     email: <email_address_for_notifications_from_Lets_Encrypt>
     server: https://acme-v02.api.letsencrypt.org/directory
     privateKeySecretRef:
      name: secret-ref
     solvers:
      - dns01:
         webhook:
           config:
             folder: <ID_of_folder_with_public_zone>
             serviceAccountSecretRef:
               name: cert-manager-secret
               key: iamkey.json
           groupName: acme.cloud.yandex.com
           solverName: yandex-cloud-dns
   ```

1. Create the `cluster-certificate.yml` file with the `Certificate` object manifest:

   ```yml
   apiVersion: cert-manager.io/v1
   kind: Certificate
   metadata:
    name: your-site
    namespace: default
   spec:
    secretName: your-site-secret
    issuerRef:
     name: clusterissuer
     kind: ClusterIssuer
    dnsNames:
      - <domain_name>
   ```

### Issue a certificate using the webhook {#run-webhook}

1. Create the objects in the Kubernetes cluster:

   ```bash
   kubectl apply -f cluster-issuer.yml && \
   kubectl apply -f cluster-certificate.yml
   ```

1. Check the certificate status:

   ```bash
   kubectl get certificate
   ```

   Result:

   ```text
   NAME        READY  SECRET            AGE
   your-site   True   your-site-secret  45m
   ```

    The `True` status in the `READY` column means that the certificate was issued successfully.

## Delete the resources you created {#clear-out}

If you no longer need the resources you created, [delete](../../managed-kubernetes/operations/kubernetes-cluster/kubernetes-cluster-delete.md) the Managed Service for Kubernetes cluster.