[Yandex Cloud documentation](../../../index.md) > [Yandex Cloud CDN](../../index.md) > [Tutorials](../index.md) > [Setting up secure content access](index.md) > Management console, CLI, and API

# Providing secure access to content in Cloud CDN using the management console, CLI, or API

To configure secure access to content in Cloud CDN:

1. [Get your cloud ready](#before-you-begin).
1. [Create a web server VM](#create-web-server).
1. [Create and configure a public DNS zone](#configure-dns).
1. [Add a TLS certificate to Yandex Certificate Manager](#issue-certificate).
1. [Prepare a source bucket for the CDN resource](#setup-bucket-origin).
1. [Create a CDN](#setup-cdn-resource).
1. [Create a CNAME resource record for the CDN resource](#create-cdn-cname-record).
1. [Publish the webiste on the web server](#publish-website).
1. [Test secure access to files](#check).

If you no longer need the resources you created, [delete them](#clear-out).


## Get your cloud ready {#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 cost of infrastructure support for setting up secure access to Cloud CDN content includes:

* Fee for using a [public IP address](../../../vpc/concepts/address.md#public-addresses) (see [Yandex Virtual Private Cloud pricing](../../../vpc/pricing.md)).
* Fee for VM computing resources and disks (see [Yandex Compute Cloud](../../../compute/pricing.md) pricing).
* Fee for using a [public DNS zone](../../../dns/concepts/dns-zone.md#public-zones) and public DNS requests (see [Yandex Cloud DNS pricing](../../../dns/pricing.md)).
* Fee for [storing data](../../../storage/concepts/bucket.md) in Object Storage, [operations](../../../storage/operations/index.md) with it, and outgoing traffic (see [Object Storage pricing](../../../storage/pricing.md)).
* Fee for outgoing traffic from [CDN servers](../../concepts/index.md) (see [Cloud CDN pricing](../../pricing.md)).


### Create a cloud network and subnet {#create-network}

{% list tabs group=instructions %}

- Management console {#console} 

  1. In the [management console](https://console.yandex.cloud), select the folder to create your resources in.
  1. Navigate to **Virtual Private Cloud**.
  1. At the top right, click **Create network**.
  1. In the **Name** field, specify `webserver-network`.
  1. In the **Advanced** field, disable the **Create subnets** option.
  1. Click **Create network**.
  1. In the left-hand panel, select ![subnets](../../../_assets/console-icons/nodes-right.svg) **Subnets**.
  1. At the top right, click **Create subnet**.
  1. In the **Name** field, specify `webserver-subnet-ru-central1-b`.
  1. In the **Availability zone** field, select the `ru-central1-b` availability zone.
  1. In the **Network** field, select `webserver-network`.
  1. In the **CIDR** field, specify `192.168.1.0/24`.
  1. Click **Create subnet**.

- Yandex Cloud CLI {#cli}

  1. Create a network named `webserver-network`:

      ```bash
      yc vpc network create webserver-network
      ```

      Result:

      ```text
      id: enp1gg8kr3pv********
      folder_id: b1gt6g8ht345********
      created_at: "2023-12-20T20:08:11Z"
      name: webserver-network
      default_security_group_id: enppne4l2eg5********
      ```

      For more information about the `yc vpc network create` command, see the [CLI reference](../../../cli/cli-ref/vpc/cli-ref/network/create.md).

  1. Create a subnet in the `ru-central1-b` availability zone:

      ```bash
      yc vpc subnet create webserver-subnet-ru-central1-b \
        --zone ru-central1-b \
        --network-name webserver-network \
        --range 192.168.1.0/24
      ```

      Result:

      ```text
      id: e2li9tcgi7ii********
      folder_id: b1gt6g8ht345********
      created_at: "2023-12-20T20:11:16Z"
      name: webserver-subnet-ru-central1-b
      network_id: enp1gg8kr3pv********
      zone_id: ru-central1-b
      v4_cidr_blocks:
        - 192.168.1.0/24
      ```

      For more information about the `yc vpc subnet create` command, see the [CLI reference](../../../cli/cli-ref/vpc/cli-ref/subnet/create.md).

- API {#api}

  1. To create a network, use the [create](../../../vpc/api-ref/Network/create.md) REST API method for the [Network](../../../vpc/api-ref/Network/index.md) resource or the [NetworkService/Create](../../../vpc/api-ref/grpc/Network/create.md) gRPC API call.

  1. To create a subnet, use the [create](../../../vpc/api-ref/Subnet/create.md) REST API method for the [Subnet](../../../vpc/api-ref/Subnet/index.md) resource or the [SubnetService/Create](../../../vpc/api-ref/grpc/Subnet/create.md) gRPC API call.

{% endlist %}


### Create a security group {#create-sg}

Create a [security group](../../../vpc/concepts/security-groups.md) that allows inbound TCP traffic on ports `22`, `80`, and `443` as well as any outbound traffic.

{% list tabs group=instructions %}

- Management console {#console}

  1. In the [management console](https://console.yandex.cloud), select the folder to create your resources in.
  1. Navigate to **Virtual Private Cloud**.
  1. In the left-hand panel, select ![image](../../../_assets/console-icons/shield.svg) **Security groups**. 
  1. Click **Create security group**.
  1. In the **Name** field, specify the name: `webserver-sg`.
  1. In the **Network** field, select `webserver-network`, which you created earlier.
  1. Under **Rules**, [create](../../../vpc/operations/security-group-add-rule.md) the following traffic management rules:

      | Traffic<br/>direction | Description | Port range | Protocol | Source /<br/>Destination name | CIDR blocks |
      | --- | --- | --- | --- | --- | --- |
      | Inbound | `http`           | `80` | `TCP` | `CIDR` | `0.0.0.0/0` |
      | Inbound | `https`            | `443`   | `TCP`  | `CIDR` | `0.0.0.0/0` |
      | Inbound | `ssh`            | `22`   | `TCP`  | `CIDR` | `0.0.0.0/0` |
      | Egress | `any`           | `All` | `Any` | `CIDR` | `0.0.0.0/0` |

  1. Click **Create**.

- Yandex Cloud CLI {#cli}
  
  Run this command:

  ```bash
  yc vpc security-group create \
    --name webserver-sg \
    --rule "description=http,direction=ingress,port=80,protocol=tcp,v4-cidrs=[0.0.0.0/0]" \
    --rule "description=https,direction=ingress,port=443,protocol=tcp,v4-cidrs=[0.0.0.0/0]" \
    --rule "description=ssh,direction=ingress,port=22,protocol=tcp,v4-cidrs=[0.0.0.0/0]" \
    --rule "description=any,direction=egress,port=any,protocol=any,v4-cidrs=[0.0.0.0/0]" \
    --network-name webserver-network
  ```

  Result:

  ```text
  id: enp4htsnl1sa********
  folder_id: b1gt6g8ht345********
  created_at: "2023-12-23T19:07:03Z"
  name: webserver-sg
  network_id: enp37qpnksl2********
  status: ACTIVE
  rules:
    - id: enpdu0t8san9********
      description: http
      direction: INGRESS
      ports:
        from_port: "80"
        to_port: "80"
      protocol_name: TCP
      protocol_number: "6"
      cidr_blocks:
        v4_cidr_blocks:
          - 0.0.0.0/0
    - id: enpr7oirpff5********
      description: https
      direction: INGRESS
      ports:
        from_port: "443"
        to_port: "443"
      protocol_name: TCP
      protocol_number: "6"
      cidr_blocks:
        v4_cidr_blocks:
          - 0.0.0.0/0
    - id: enp0bgk6dkdd********
      description: ssh
      direction: INGRESS
      ports:
        from_port: "22"
        to_port: "22"
      protocol_name: TCP
      protocol_number: "6"
      cidr_blocks:
        v4_cidr_blocks:
          - 0.0.0.0/0
    - id: enpspns0tfml********
      description: any
      direction: EGRESS
      protocol_name: ANY
      protocol_number: "-1"
      cidr_blocks:
        v4_cidr_blocks:
          - 0.0.0.0/0
  ```

  For more information about the `yc vpc security-group create` command, see the [CLI reference](../../../cli/cli-ref/vpc/cli-ref/security-group/create.md).

  Save the security group ID (`id`), as you will need it to create a VM.

- API {#api}

  To create a security group, use the [create](../../../vpc/api-ref/SecurityGroup/create.md) REST API method for the [SecurityGroup](../../../vpc/api-ref/SecurityGroup/index.md) resource or the [SecurityGroupService/Create](../../../vpc/api-ref/grpc/SecurityGroup/create.md) gRPC API call.

{% endlist %}


### Prepare files for uploading to the bucket {#prepare-files}

1. Save any image in JPEG format to the `content.jpg` file.
1. Create a file named `index.html`:

    ```html
    <html>
        <body>
        </body>
    </html>
    ```


## Create a web server VM {#create-web-server}

Before you start, prepare a [key pair](../../../compute/operations/vm-connect/ssh.md#creating-ssh-keys) (public and private keys) to access your VM over SSH.

{% list tabs group=instructions %}

- Management console {#console}

  1. In the [management console](https://console.yandex.cloud), navigate to the [folder](../../../resource-manager/concepts/resources-hierarchy.md#folder) dashboard, click **Create resource**, and select `Virtual machine instance`.
  1. Under **Boot disk image**, in the **Product search** field, specify `LAMP` and select the [LAMP](https://yandex.cloud/en/marketplace/products/yc/lamp) image.
  1. Under **Location**, select the `ru-central1-b` [availability zone](../../../overview/concepts/geo-scope.md).
  1. Under **Network settings**:

      * In the **Subnet** field, select the `webserver-subnet-ru-central1-b` subnet you created earlier.
      * In the **Public IP address** field, select `Auto`.
      * In the **Security groups** field, select `webserver-sg`.

  1. Under **Access**, select **SSH key** and specify the VM access credentials:

      * In the **Login** field, specify the username: `yc-user`.
      * In the **SSH key** field, select the SSH key saved in your [organization user](../../../organization/concepts/membership.md) profile.
        
        If there are no SSH keys in your profile or you want to add a new key:
        
        1. Click **Add key**.
        1. Enter a name for the SSH key.
        1. Select one of the following:
        
            * `Enter manually`: Paste the contents of the public SSH key. You need to [create](../../../compute/operations/vm-connect/ssh.md#creating-ssh-keys) an SSH key pair on your own.
            * `Load from file`: Upload the public part of the SSH key. You need to create an SSH key pair on your own.
            * `Generate key`: Automatically create an SSH key pair.
            
              When adding a new SSH key, an archive containing the key pair will be created and downloaded. In Linux or macOS-based operating systems, unpack the archive to the `/home/<user_name>/.ssh` directory. In Windows, unpack the archive to the `C:\Users\<user_name>/.ssh` directory. You do not need additionally enter the public key in the management console.
        
        1. Click **Add**.
        
        The system will add the SSH key to your organization user profile. If the organization has [disabled](../../../organization/operations/os-login-access.md) the ability for users to add SSH keys to their profiles, the added public SSH key will only be saved in the user profile inside the newly created resource.

  1. Under **General information**, specify the VM name: `mywebserver`.
  1. Click **Create VM**.

- Yandex Cloud CLI {#cli}

  Run this command:

  ```bash
  yc compute instance create \
    --name mywebserver \
    --zone ru-central1-b \
    --network-interface subnet-name=webserver-subnet-ru-central1-b,nat-ip-version=ipv4,security-group-ids=<security_group_ID> \
    --create-boot-disk image-folder-id=standard-images,image-id=fd8jtn9i7e9ha5q25niu \
    --ssh-key ~/.ssh/id_ed25519.pub
  ```

  Where:
  * `<security_group_ID>`: Security group ID you saved earlier.
  * `--ssh-key`: Path to the file with the public SSH key, e.g., `~/.ssh/id_ed25519.pub`.

  Result:

  ```text
  done (32s)
  id: fhmaq4shfrcm********
  folder_id: b1gt6g8ht345********
  created_at: "2023-12-23T05:36:34Z"
  name: mywebserver
  zone_id: ru-central1-b
  platform_id: standard-v2
  resources:
    memory: "2147483648"
    cores: "2"
    core_fraction: "100"
  status: RUNNING
  metadata_options:
    gce_http_endpoint: ENABLED
    aws_v1_http_endpoint: ENABLED
    gce_http_token: ENABLED
    aws_v1_http_token: DISABLED
  boot_disk:
    mode: READ_WRITE
    device_name: fhmprher1d0q********
    auto_delete: true
    disk_id: fhmprher1d0q********
  network_interfaces:
    - index: "0"
      mac_address: d0:0d:ad:13:91:7e
      subnet_id: e9bk1m87r4m4********
      primary_v4_address:
        address: 192.168.1.11
        one_to_one_nat:
          address: 158.160.***.***
          ip_version: IPV4
      security_group_ids:
        - enpa5j0mrgm4********
  gpu_settings: {}
  fqdn: fhmaq4shfrcm********.auto.internal
  scheduling_policy: {}
  network_settings:
    type: STANDARD
  placement_policy: {}
  ```

  For more information about the `yc compute instance create` command, see the [CLI reference](../../../cli/cli-ref/compute/cli-ref/instance/create.md).

- API {#api}

  To create a VM, use the [create](../../../compute/api-ref/Instance/create.md) REST API method for the [Instance](../../../compute/api-ref/Instance/index.md) resource or the [InstanceService/Create](../../../compute/api-ref/grpc/Instance/create.md) gRPC API call.

{% endlist %}

This will create a VM named `mywebserver` in your folder. To [connect](../../../compute/operations/vm-connect/ssh.md#vm-connect) to the VM over SSH, use the `yc-user` username and the [public IP address](../../../vpc/concepts/address.md#public-addresses) of the VM. If you plan to use the created web server over a long period of time, [make](../../../vpc/operations/set-static-ip.md) this VM's public IP address static.


## Create and configure a public DNS zone {#configure-dns}

1. Create a public [DNS zone](../../../dns/concepts/dns-zone.md) in Yandex Cloud DNS.

    {% list tabs group=instructions %}

    - Management console {#console}

      1. In the [management console](https://console.yandex.cloud), select the folder to create your resources in.
      1. Navigate to **Cloud DNS**.
      1. Click **Create zone**.
      1. Specify the zone settings consistent with your domain:

         1. **Zone**: Domain zone. Its name must end with a trailing dot. For example, `example.com.` matches the `example.com` domain. To create a domain name with non-Latin characters, use the [Punycode](https://en.wikipedia.org/wiki/Punycode) encoding.
         1. **Type**: `Public`.
         1. **Name**: `my-domain-zone`.

      1. Click **Create**.

    - Yandex Cloud CLI {#cli}

      Run this command:

      ```bash
      yc dns zone create \
        --name my-domain-zone \
        --zone <domain_name> \
        --public-visibility
      ```

      Where `--zone` is your domain's name, e.g., `example.com.`. The `--zone` parameter value must end with a trailing dot. For example, `example.com.` matches the `example.com` domain.

      Result:

      ```
      id: dns39gihj0ef********
      folder_id: b1gt6g8ht345********
      created_at: "2023-12-21T16:43:37.883Z"
      name: my-domain-zone
      zone: example.com.
      public_visibility: {}
      ```

      For more information about the `yc dns zone create` command, see the [CLI reference](../../../cli/cli-ref/dns/cli-ref/zone/create.md).

    - API {#api}

      To create a public DNS zone, use the [create](../../../dns/api-ref/DnsZone/create.md) REST API method for the [DnsZone](../../../dns/api-ref/DnsZone/index.md) resource or the [DnsZoneService/Create](../../../dns/api-ref/grpc/DnsZone/create.md) gRPC API call.

    {% endlist %}

1. Delegate your domain to Cloud DNS. To do this, in your domain registrar's account, specify the addresses of these DNS servers in your domain settings: `ns1.yandexcloud.net` and `ns2.yandexcloud.net`.

1. In your DNS zone, create an `A` resource record pointing to the public IP address of the web server VM you created earlier:

    {% list tabs group=instructions %}

    - Management console {#console}

      1. In the [management console](https://console.yandex.cloud), select the folder to create your resources in.
      1. Navigate to **Cloud DNS**.
      1. Select the DNS zone you created earlier.
      1. Click **Create record**.
      1. Specify the record settings:
         1. In the **Name** field, select `Matches zone name (@)`.
         1. In the **Type** field, select the `A` [record type](../../../dns/concepts/resource-record.md#rr-types).
         1. In the **Data** field, specify the [public IP address](../../../vpc/concepts/address.md#public-addresses) of the web server VM you created earlier.

             You can find your VM’s IP address on the VM page in the [management console](https://console.yandex.cloud), under **Network**, or using the `yc compute instance get mywebserver` CLI command.

      1. Click **Create**.

    - Yandex Cloud CLI {#cli}

      Run this command:

      ```bash
      yc dns zone add-records \
        --name my-domain-zone \
        --record "@ 600 A <VM_IP_address>"
      ```

      Where `<VM_IP_address>` is the [public IP address](../../../vpc/concepts/address.md#public-addresses) of the web server VM you created earlier.

      You can find your VM’s IP address on the VM page in the [management console](https://console.yandex.cloud), under **Network**, or using the `yc compute instance get mywebserver` CLI command.

      Result:

      ```text
      +--------+--------------+------+---------------+-----+
      | ACTION |     NAME     | TYPE |     DATA      | TTL |
      +--------+--------------+------+---------------+-----+
      | +      | example.com. | A    | 51.250.**.*** | 600 |
      +--------+--------------+------+---------------+-----+
      ```

      For more information about the `yc dns zone add-records` command, see the [CLI reference](../../../cli/cli-ref/dns/cli-ref/zone/add-records.md).

    - API {#api}

      To create a resource record in a DNS zone, use the [updateRecordSets](../../../dns/api-ref/DnsZone/updateRecordSets.md) REST API method for the [DnsZone](../../../dns/api-ref/DnsZone/index.md) resource or the [DnsZoneService/UpdateRecordSets](../../../dns/api-ref/grpc/DnsZone/updateRecordSets.md) gRPC API call.

    {% endlist %}


## Add a TLS certificate to Yandex Certificate Manager {#issue-certificate}

1. Add a Let's Encrypt® [certificate](../../../certificate-manager/concepts/managed-certificate.md) to Certificate Manager for your domains that the web server and CDN resource will use.

    {% list tabs group=instructions %}

    - Management console {#console}

      1. In the [management console](https://console.yandex.cloud), select the folder to create your resources in.
      1. Navigate to **Certificate Manager**.
      1. Click **Add certificate** and select **Let's Encrypt certificate**.
      1. In the window that opens, specify `mymanagedcert` in the **Name** field.
      1. In the **Domains** field, specify your domain name, e.g., `example.com`.

          In a new line within the same field, specify the name of the subdomain to serve the CDN resource, e.g., `cdn.example.com`.
      1. Select the [domain rights check type](../../../certificate-manager/concepts/challenges.md): `DNS`.
      1. Click **Create**.

    - Yandex Cloud CLI {#cli}

      Run this command:

      ```bash
      yc certificate-manager certificate request \
        --name mymanagedcert \
        --challenge dns \
        --domains <domain_name>,<subdomain_name>
      ```

      Where:
      * `<domain_name>`: Name of your domain for the web server, e.g., `example.com`.
      * `<subdomain_name>`: Name of the subdomain the CDN resource will use, e.g., `cdn.example.com`.

      Result:
      ```bash
      id: fpqbs12t6ion********
      folder_id: b1gt6g8ht345********
      created_at: "2023-12-24T14:36:39.299844798Z"
      name: mymanagedcert
      type: MANAGED
      domains:
        - example.com
        - cdn.example.com
      status: VALIDATING
      updated_at: "2023-12-24T14:36:39.299844798Z"
      ```

      For more information about the `yc certificate-manager certificate request` command, see the [CLI reference](../../../cli/cli-ref/certificate-manager/cli-ref/certificate/request.md).

      Save the ID (`id`) of the certificate you created, as you will need it when creating a CDN resource.

    - API {#api}

      To add a certificate, use the [requestNew](../../../certificate-manager/api-ref/Certificate/requestNew.md) REST API method for the [Certificate](../../../certificate-manager/api-ref/Certificate/index.md) resource or the [CertificateService/RequestNew](../../../certificate-manager/api-ref/grpc/Certificate/requestNew.md) gRPC API call.

    {% endlist %}

    A new certificate with the `Validating` status will appear in the certificate list. This status means that a Let's Encrypt® certificate was requested and you need to pass [domain ownership verification](../../../certificate-manager/operations/managed/cert-validate.md) for it to be successfully processed.

1. For the certificate to be issued successfully, pass domain ownership verification:

    {% list tabs group=instructions %}

    - Management console {#console}

        1. In the [management console](https://console.yandex.cloud), select the folder to create your resources in.
        1. Navigate to **Certificate Manager**.
        1. From the list of certificates, select `mymanagedcert`.
        1. In the window that opens, under **Check rights for domains**, select `CNAME record`.
        1. In the first domain section, click **Create record** and then **Create** in the window that opens.
        1. Repeat the above action for the second domain.

        Domain ownership verification may take from a few minutes to a few days. Wait until it successfully completes. As a result, the certificate will be issued and get the `Issued` status.

    - Yandex Cloud CLI {#cli}

        1. Get the values of the resource records required for passing the check:

            ```bash
            yc certificate-manager certificate get \
              --name mymanagedcert \
              --full
            ```

            Result:

            ```bash
            id: fpq2gpi42teg********
            folder_id: b1gt6g8ht345********
            created_at: "2023-12-24T18:13:45.960Z"
            name: mymanagedcert
            type: MANAGED
            domains:
              - example.com
              - cdn.example.com
            status: VALIDATING
            updated_at: "2023-12-24T18:13:45.960Z"
            challenges:
              - domain: cdn.example.com
                type: DNS
                created_at: "2023-12-24T18:13:45.960Z"
                updated_at: "2023-12-24T18:13:49.280Z"
                status: PENDING
                message: Create a record in your DNS provider.
                dns_challenge:
                  name: _acme-challenge.cdn.example.com.
                  type: CNAME
                  value: fpq2gpi42teg********.cm.yandexcloud.net.
              - domain: cdn.example.com
                type: DNS
                created_at: "2023-12-24T18:13:45.960Z"
                updated_at: "2023-12-24T18:13:49.280Z"
                status: PENDING
                message: Create a record in your DNS provider.
                dns_challenge:
                  name: _acme-challenge.cdn.example.com.
                  type: TXT
                  value: d9RzZH8WZucSY8mXs9cEg1wNteaaNqbxZK7********
              - domain: example.com
                type: DNS
                created_at: "2023-12-24T18:13:45.960Z"
                updated_at: "2023-12-24T18:13:49.280Z"
                status: PENDING
                message: Create a record in your DNS provider.
                dns_challenge:
                  name: _acme-challenge.example.com
                  type: CNAME
                  value: fpq2gpi42teg********.cm.yandexcloud.net.
              - domain: example.com
                type: DNS
                created_at: "2023-12-24T18:13:45.960Z"
                updated_at: "2023-12-24T18:13:49.280Z"
                status: PENDING
                message: Create a record in your DNS provider.
                dns_challenge:
                  name: _acme-challenge.example.com.
                  type: TXT
                  value: iiyJJJlsaFIqQ7DMUzira0OKU3iXuaqiN7U********
            ```

            For more information about the `yc certificate-manager certificate get` command, see the [CLI reference](../../../cli/cli-ref/certificate-manager/cli-ref/certificate/get.md).

            Save the values of the `value` fields from the `CNAME` type sections under `challenges.dns_challenge` for both domain names. You will need them in the next step.

        1. Create CNAME [resource records](../../../dns/concepts/resource-record.md) to pass domain ownership verification:

            ```bash
            yc dns zone add-records \
              --name my-domain-zone \
              --record "_acme-challenge 600 CNAME <dns_challenge_value>" \
              --record "_acme-challenge.<subdomain> 600 CNAME <dns_challenge_value>"
            ```

            Where:
            * `<dns_challenge_value>`: Value saved in the previous step required to check you rights to the relevant domain using a CNAME record.
            * `<subdomain>`: Name you gave to the CDN resource subdomain, e.g., `cdn`. In this case, the record will look as follows: `_acme-challenge.cdn 600 CNAME fpq2gpi42teg********.cm.yandexcloud.net.`. 

            Result:

            ```text
            +--------+----------------------------------+-------+------------------------------------------+-----+
            | ACTION |              NAME                | TYPE  |                   DATA                   | TTL |
            +--------+----------------------------------+-------+------------------------------------------+-----+
            | +      | _acme-challenge.cdn.example.com. | CNAME | fpq2gpi42teg********.cm.yandexcloud.net. | 600 |
            | +      | _acme-challenge.example.com.     | CNAME | fpq2gpi42teg********.cm.yandexcloud.net. | 600 |
            +--------+----------------------------------+-------+------------------------------------------+-----+
            ```

            For more information about the `yc dns zone add-records` command, see the [CLI reference](../../../cli/cli-ref/dns/cli-ref/zone/add-records.md).

            Domain ownership verification may take from a few minutes to a few days. Wait until it successfully completes. As a result, the certificate will be issued and get the `Issued` status.

        1. Make sure that the certificate status has switched to `Issued`:

            ```bash
            yc certificate-manager certificate get \
              --name mymanagedcert
            ```

            Result:

            ```text
            id: fpqr2j0sdb1n********
            folder_id: b1gt6g8ht345********
            created_at: "2023-12-24T16:38:02.206Z"
            name: mymanagedcert
            type: MANAGED
            domains:
              - cdn.example.com
              - example.com
            status: ISSUED
            issuer: CN=R3,O=Let's Encrypt,C=US
            subject: CN=cdn.example.com
            serial: 4b7d7f0968097ae1a7707854a80********
            updated_at: "2023-12-24T16:46:03.578Z"
            issued_at: "2023-12-24T16:46:03.578Z"
            not_after: "2024-03-23T15:44:59Z"
            not_before: "2023-12-24T15:45:00Z"
            ```

    - API {#api}

      To get the information required to pass domain ownership verification, use the [get](../../../certificate-manager/api-ref/Certificate/get.md) REST API method for the [Certificate](../../../certificate-manager/api-ref/Certificate/index.md) resource or the [CertificateService/Get](../../../certificate-manager/api-ref/grpc/Certificate/get.md) gRPC API call with the `view=FULL` flag.
      
      To create a CNAME resource record in a DNS zone, use the [updateRecordSets](../../../dns/api-ref/DnsZone/updateRecordSets.md) REST API method for the [DnsZone](../../../dns/api-ref/DnsZone/index.md) resource or the [DnsZoneService/UpdateRecordSets](../../../dns/api-ref/grpc/DnsZone/updateRecordSets.md) gRPC API call.

    {% endlist %}

    {% note info %}

    For a successful DNS domain rights check based on a `CNAME` record, make sure the `_acme-challenge` subdomain of the domain name you are checking has no other [resource records](../../../dns/concepts/resource-record.md) except `CNAME`. For example, for the `_acme-challenge.example.com.` domain name, there should only be a CNAME record and no TXT record.

    {% endnote %}


## Prepare a source bucket for the CDN resource {#setup-bucket-origin}.

1. Create an Object Storage bucket to serve as a [source](../../concepts/origins.md) for the CDN resource. The [bucket name](../../../storage/concepts/bucket.md#naming) must be unique.

    {% list tabs group=instructions %}

    - Management console {#console}

      1. In the [management console](https://console.yandex.cloud), select the folder to create your resources in.
      1. Navigate to **Object Storage**.
      1. At the top right, click **Create bucket**.
      1. In the ** Name** field, enter a name for the bucket, e.g., `cdn-source-bucket`.
      1. In the **Max size** field, specify `1 GB`.
      1. In the **Read objects** and **Read object list** fields, select `For all`.
      1. Click **Create bucket**.
      1. On the page with the list of buckets, select the one you created.
      1. In the left-hand panel, select **Settings**.
      1. On the **Website** tab:
         * Select `Hosting`.
         * In the **Home page** field, specify `index.html`.
      1. Click **Save**.

    - Yandex Cloud CLI {#cli}

      1. Create a bucket:

          ```bash
          yc storage bucket create \
            --name <bucket_name> \
            --default-storage-class standard \
            --max-size 1073741824 \
            --public-read \
            --public-list
          ```

          Where `--name` is the bucket name unique throughout Object Storage, e.g., `cdn-source-bucket`.

          Result:

          ```text
          name: cdn-source-bucket
          folder_id: b1gt6g8ht345********
          anonymous_access_flags:
            read: false
            list: false
          default_storage_class: STANDARD
          versioning: VERSIONING_DISABLED
          max_size: "1073741824"
          acl: {}
          created_at: "2023-12-22T18:11:23.028836Z"
          ```

          For more information about the `yc storage bucket create` command, see the [CLI reference](../../../cli/cli-ref/storage/cli-ref/bucket/create.md).

      1. Enable static website hosting in the bucket:

          ```bash
          yc storage bucket update \
            --name <bucket_name> \
            --website-settings '{"index": "index.html"}'
          ```

          Result:

          ```text
          name: cdn-source-bucket
          folder_id: b1gt6g8ht345********
          default_storage_class: STANDARD
          versioning: VERSIONING_DISABLED
          max_size: "1073741824"
          acl: {}
          created_at: "2023-12-23T09:56:58.249721Z"
          website_settings:
            redirect_all_requests: {}
          ```

          For more information about the `yc storage bucket update` command, see the [CLI reference](../../../cli/cli-ref/storage/cli-ref/bucket/update.md).

    - AWS CLI {#aws-cli}

      If you do not have the AWS CLI yet, [install and configure it](../../../storage/tools/aws-cli.md).

      [Assign](../../../iam/operations/sa/assign-role-for-sa.md) the `storage.editor` [role](../../../storage/security/index.md#storage-editor) to the service account the AWS CLI uses.

      1. Create a bucket:

          ```bash
          aws s3api create-bucket \
            --endpoint-url https://storage.yandexcloud.net \
            --bucket <bucket_name> \
            --acl public-read
          ```

          Where `--bucket` is the bucket name unique throughout Object Storage, e.g., `cdn-source-bucket`.

          Result:

          ```json
          {
              "Location": "/cdn-source-bucket"
          }
          ```

      1. Enable static website hosting in the bucket:

          ```bash
          aws --endpoint-url https://storage.yandexcloud.net \
            s3 website "s3://<bucket_name>" \
            --index-document index.html
          ```

          Where `<bucket_name>` is the name of the bucket you created earlier, e.g., `cdn-source-bucket`.

    - API {#api}

      To create a bucket, use the [create](../../../storage/api-ref/Bucket/create.md) REST API method for the [Bucket](../../../storage/api-ref/Bucket/index.md) resource, the [BucketService/Create](../../../storage/api-ref/grpc/Bucket/create.md) gRPC API call, or the [create](../../../storage/s3/api-ref/bucket/create.md) S3 API method.

      To enable static website hosting in the bucket, use the [update](../../../storage/api-ref/Bucket/update.md) REST API method for the [Bucket](../../../storage/api-ref/Bucket/index.md) resource, the [BucketService/Update](../../../storage/api-ref/grpc/Bucket/update.md) gRPC API call, or the [upload](../../../storage/s3/api-ref/hosting/upload.md) S3 API method.

    {% endlist %}

1. Upload the [prepared](#prepare-files) files to the bucket:

    {% list tabs group=instructions %}

    - Management console {#console}

      1. In the [management console](https://console.yandex.cloud), select the folder to create your resources in.
      1. Navigate to **Object Storage**.
      1. Select the bucket you created ealier.
      1. In the top-right corner, click ![image](../../../_assets/console-icons/arrow-up-from-line.svg) **Upload** and select the files you created: `index.html` and `content.jpg`.
      1. In the window that opens, confirm uploading the objects.

    - AWS CLI {#cli}

      1. Upload the `index.html` file to the bucket:

          ```bash
          aws --endpoint-url https://storage.yandexcloud.net \
            s3 cp ./index.html s3://<bucket_name>/index.html
          ```

          Where `<bucket_name>` is the name of the bucket you created earlier, e.g., `cdn-source-bucket`.

          Result:

          ```txt
          upload: ./index.html to s3://cdn-source-bucket/index.html
          ```

      1. Upload the `content.jpg` file to the bucket:

          ```bash
          aws --endpoint-url https://storage.yandexcloud.net \
            s3 cp ./content.jpg s3://<bucket_name>/content.jpg
          ```

          Result:

          ```txt
          upload: ./content.jpg to s3://cdn-source-bucket/content.jpg
          ```

    - API {#api}

      To upload files to the bucket, use the [upload](../../../storage/s3/api-ref/object/upload.md) S3 API method.

    {% endlist %}


## Create a CDN {#setup-cdn-resource}

{% list tabs group=instructions %}

- Management console {#console}

  1. In the [management console](https://console.yandex.cloud), select the folder to create your resources in.
  1. Navigate to **Cloud CDN**.
  1. Click **Create resource**.
  1. Configure the basic CDN resource settings:
      * Under **Content**:
        * Enable **Enable access to content**.
        * In the **Content query** field, select `From one origin`.
        * In the **Origin type** field, select `Server`.
        * In the **Origin domain name** field, specify `<bucket_name>.website.yandexcloud.net`, where `<bucket_name>` is the name of the bucket you created earlier, which the CDN resource uses as a source.
        * In the **Origin request protocol** field, select `Match client`.
        * In the **Domain name** field, specify the domain name you intend to assign to your CDN resource, e.g., `cdn.example.com`.
      * Under **Additional settings**:
        * In the **Redirect clients** field, select `Don't use`.
        * In the **Certificate type** field, select `Use from Certificate Manager` and then the `mymanagedcert` certificate you created earlier from the list that opens.
        * In the **Host header** field, select `Custom`. Then, in the **Header value** field that opens, specify `<bucket_name>.website.yandexcloud.net`, where `<bucket_name>` is the name of the bucket you created earlier, which the CDN resource uses as a source.
        * Enable **Access via secure token**:
          1. In the **Secret key** fieled that appears, specify a secret key, a string of 6 to 32 characters. It will be transmitted to the CDN resource configuration and used to generate and check signed links.
          1. In the **Limit access by IP address** field, select `Only trusted IP addresses`.
  1. Click **Continue**.
  1. Under **Caching**, **HTTP headers and methods**, and **Advanced**, leave the default settings, then click **Continue**.

- Yandex Cloud CLI {#cli}

  1. Create a resource:
  
      ```bash
      yc cdn resource create <subdomain_name> \
        --origin-custom-source <bucket_name>.website.yandexcloud.net \
        --origin-protocol 'match' \
        --cert-manager-ssl-cert-id <certificate_ID> \
        --host-header <bucket_name>.website.yandexcloud.net \
        --secure-key <secret_key> \
        --enable-ip-url-signing
      ```

      Where:
      * `<subdomain_name>`: Domain name for which the TLS certificate was created earlier and which the CDN resource will use, e.g., `cdn.example.com`.
      * `<bucket_name>`: Name of the Object Storage bucket you created earlier, e.g., `cdn-source-bucket`.
      * `--cert-manager-ssl-cert-id`: TLS certificate ID that you saved earlier when creating the certificate.
      * `--secure-key`: Secret key, a string of 6 to 32 characters. The secret key will be transmitted to the CDN resource configuration and used to generate and check signed links.

      Result:

      ```text
      id: bc8yqhobvxk6********
      folder_id: b1gt6g8ht345********
      cname: cdn.example.com
      created_at: "2024-06-22T19:59:05.430376Z"
      updated_at: "2024-06-22T19:59:05.430394Z"
      active: true
      options:
        edge_cache_settings:
          enabled: true
          default_value: "345600"
        query_params_options:
          ignore_query_string:
            enabled: true
            value: true
        host_options:
          host:
            enabled: true
            value: cdn-source-bucket.website.yandexcloud.net
        stale:
          enabled: true
          value:
            - error
            - updating
        secure_key:
          enabled: true
          key: sdh********
          type: ENABLE_IP_SIGNING
      origin_group_id: "310699"
      origin_group_name: Origins for cdn.example.com (211929)
      origin_protocol: MATCH
      ssl_certificate:
        type: CM
        status: READY
        data:
          cm:
            id: fpqia0s2fc21********
      provider_type: ourcdn
      provider_cname: d88c6ee6********.topology.gslb.yccdn.ru
      ```

      Save the provider’s CNAME value (the `provider_cname` field) for later.

      For more information about the `yc cdn resource create` command, see the [CLI reference](../../../cli/cli-ref/cdn/cli-ref/resource/create.md).

- API {#api}

  Use the [create](../../api-ref/Resource/create.md) REST API method for the [Resource](../../api-ref/Resource/index.md) resource or the [ResourceService/Create](../../api-ref/grpc/Resource/create.md) gRPC API call.

{% endlist %}

It may take up to 15 minutes for the new settings of the existing resource to apply to the CDN servers. After that, we recommend [purging the resource cache](../../operations/resources/purge-cache.md).

The content on the new CDN resource will be accessible only via [signed links](../../concepts/secure-tokens.md#protected-link).

## Create a CNAME resource record for the CDN resource {#create-cdn-cname-record}

{% list tabs group=instructions %}

- Management console {#console}

  1. [Get](../../operations/resources/get-resources-info.md#get-cname) the CDN provider domain name value.
  1. In the [management console](https://console.yandex.cloud), select the folder to create your resources in.
  1. Navigate to **Cloud DNS**.
  1. Select the DNS zone you created earlier.
  1. Click **Create record**.
  1. Specify the record settings:

        * In the **Name** field, select `Create subdomain` and specify the name you gave to the CDN resource subdomain. For example, if the domain name of your CDN resource is `cdn.example.com`, put `cdn` only.
        * In the **Type** field, select the `CNAME` [record type](../../../dns/concepts/resource-record.md#rr-types).
        * In the **Data** field, specify the [domain name](../../operations/resources/get-resources-info.md#get-cname) value of the CDN provider.

  1. Click **Create**.

- Yandex Cloud CLI {#cli}

  1. Create a CNAME resource record in Cloud DNS:

      ```bash
      yc dns zone add-records \
        --name my-domain-zone \
        --record "<subdomain> 600 CNAME <cname_value>"
      ```

      Where:
      * `<subdomain>`: Subdomain created for the CDN resource. For example, for the `cdn.example.com` domain name, specify `cdn`.
      * `<cname_value>`: CDN provider’s `cname` value you got in the previous step.

      Result:

      ```text
      +--------+------------------+-------+-------------------------------------------+-----+
      | ACTION |       NAME       | TYPE  |           DATA                            | TTL |
      +--------+------------------+-------+-------------------------------------------+-----+
      | +      | cdn.example.com. | CNAME | e1b83ae3********.topology.gslb.yccdn.ru | 600 |
      +--------+------------------+-------+-------------------------------------------+-----+
      ```

      For more information about the `yc dns zone add-records` command, see the [CLI reference](../../../cli/cli-ref/dns/cli-ref/zone/add-records.md).

- API {#api}

  To get the CNAME record value for a CDN resource, use the [getProviderCName](../../api-ref/Resource/getProviderCName.md) REST API method for the [Resource](../../api-ref/Resource/index.md) resource or the [ResourceService/GetProviderCName](../../api-ref/grpc/Resource/getProviderCName.md) gRPC API call.

  To create a CNAME resource record in a DNS zone, use the [updateRecordSets](../../../dns/api-ref/DnsZone/updateRecordSets.md) REST API method for the [DnsZone](../../../dns/api-ref/DnsZone/index.md) resource or the [DnsZoneService/UpdateRecordSets](../../../dns/api-ref/grpc/DnsZone/updateRecordSets.md) gRPC API call.

{% endlist %}


## Publish the webiste on the web server {#publish-website}

Next, you will create and publish on your web server a website that will generate signed links to content hosted on the secure CDN resource. For data transfer security, you will copy the previously created TLS certificate to the same web server and enable SSL encryption.


### Download the certificate from Certificate Manager {#export-certificate}

To use the TLS certificate created in Certificate Manager in your web server configuration, download the certificate chain and private key to the current directory:

{% list tabs group=instructions %}

- Yandex Cloud CLI {#cli}

  1. Learn the ID of the previously created TLS certificate:

      ```bash
      yc certificate-manager certificate list
      ```

      Result:

      ```text
      +----------------------+---------------+-----------------------------+---------------------+---------+--------+
      |          ID          |     NAME      |           DOMAINS           |      NOT AFTER      |  TYPE   | STATUS |
      +----------------------+---------------+-----------------------------+---------------------+---------+--------+
      | fpq90lobsh0l******** | mymanagedcert | cdn.example.com,example.com | 2024-03-22 16:42:53 | MANAGED | ISSUED |
      +----------------------+---------------+-----------------------------+---------------------+---------+--------+
      ```

      For more information about the `yc certificate-manager certificate list` command, see the [CLI reference](../../../cli/cli-ref/certificate-manager/cli-ref/certificate/list.md).

  1. Download the key and certificate by specifying the ID you got in the previous step:

      ```bash
      yc certificate-manager certificate content \
        --id <certificate_ID> \
        --chain ./certificate_full_chain.pem \
        --key ./private_key.pem
      ```

      For more information about the `yc certificate-manager certificate content` command, see the [CLI reference](../../../cli/cli-ref/certificate-manager/cli-ref/certificate/content.md).

{% endlist %}


### Configure the web server {#setup-web-server}

1. Copy the certificates and private key thus obtained to the VM hosting the web server:

    ```bash
    scp ./certificate_full_chain.pem yc-user@<VM_IP_address>:certificate_full_chain.pem \
      && scp ./private_key.pem yc-user@<VM_IP_address>:private_key.pem
    ```

    Where `<VM_IP_address>` is the public IP address of the previously created VM with a web server.

    You can find the IP address of your VM in the [management console](https://console.yandex.cloud) on the VM page under **Network** or using the `yc compute instance get mywebserver` CLI command.

    If this is your first time connecting to the VM, you will see an unknown host warning:

    ```text
    The authenticity of host '51.250.**.*** (51.250.**.***)' can't be established.
    ED25519 key fingerprint is SHA256:PpcKdcT09gjU045pkEIwIU8lAXXLpwJ6bKC********.
    This key is not known by any other names
    Are you sure you want to continue connecting (yes/no/[fingerprint])?
    ```

    Type `yes` in the terminal and press **Enter**.

1. [Connect](../../../compute/operations/vm-connect/ssh.md) to the VM with the web server:

    ```bash
    ssh yc-user@<VM_IP_address>
    ```

1. Create a directory for the certificate and move the copied files there:

    ```bash
    sudo mkdir /etc/ssl-certificates
    sudo mv certificate_full_chain.pem /etc/ssl-certificates/
    sudo mv private_key.pem /etc/ssl-certificates/
    ```

1. Create a directory for your website files and grant the required permissions for it to the `www-data` user:

    ```bash
    sudo mkdir -p /var/www/<domain_name>/public_html
    sudo chown www-data:www-data /var/www/<domain_name>/public_html
    ```

    Where `<domain_name>` is the domain name of your website, e.g., `example.com`.

1. Configure a virtual host for your website:

    1. Create a virtual host configuration file:

        ```bash
        sudo nano /etc/apache2/sites-available/mywebsite.conf
        ```

    1. Add the following configuration into the file:

        ```text
        <VirtualHost *:443>
        ServerName <domain_name>
        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/<domain_name>/public_html
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
        SSLEngine on
        SSLCertificateFile /etc/ssl-certificates/certificate_full_chain.pem
        SSLCertificateChainFile /etc/ssl-certificates/certificate_full_chain.pem
        SSLCertificateKeyFile /etc/ssl-certificates/private_key.pem
        </VirtualHost>
        ```

        Where `<domain_name>` is the domain name of your website, e.g., `example.com`.

    1. Activate the virtual host you created:

        ```bash
        sudo a2ensite mywebsite
        ```

        Result:

        ```text
        Enabling site mywebsite.
        To activate the new configuration, you need to run:
          systemctl reload apache2
        ```

    1. Enable `ssl` for the web server:

        ```bash
        sudo a2enmod ssl
        ```

        Result:

        ```text
        Considering dependency setenvif for ssl:
        Module setenvif already enabled
        Considering dependency mime for ssl:
        Module mime already enabled
        Considering dependency socache_shmcb for ssl:
        Enabling module socache_shmcb.
        Enabling module ssl.
        See /usr/share/doc/apache2/README.Debian.gz on how to configure SSL and create self-signed certificates.
        To activate the new configuration, you need to run:
          systemctl restart apache2
        ```

    1. Restart the web server:

        ```bash
        sudo systemctl reload apache2
        ```


### Create a website {#create-website}

1. Create the home page file for the website:

    ```bash
    sudo nano /var/www/<domain_name>/public_html/index.php
    ```

    Where `<domain_name>` is the domain name of your website, e.g., `example.com`.

1. Add the following code into the `index.php` file you created:

    ```php
    <!DOCTYPE html>
    <html>
    <head>
      <title>Secure token generator website</title>
      <meta charset="utf-8" />
    </head>
    <body>

      <h2>Secure link generator</h2>
      <p>Below, a signed link to the secure CDN resource has been generated. The link is valid for five minutes. The content at this link is available only to the user the link was generated for by the website (verified by IP address).</p>
      <br>

      <?php

        $secret = '<secret_key>';
        $ip = trim(getUserIpAddr());
        $domain_name = '<domain_name>';
        $path = '<object_key>';
        $expires = time() + 300;
        $link = "$expires$path$ip $secret";
        $md5 = md5($link, true);
        $md5 = base64_encode($md5);
        $md5 = strtr($md5, '+/', '-_');
        $md5 = str_replace('=', '', $md5);
        $url = '<a href="https://'.$domain_name.$path.'?md5='.$md5.'&expires='.$expires.'" target="_blank">Signed link to file</a>';
    
        echo "<p>Your IP address: <b>".$ip."</b></p><p>If you are using a VPN, you link may not work. For the signed link generator to work properly, disable your VPN.</p>";
        echo "<br><br>";
        echo $url;
    
        function getUserIpAddr() {

            if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
               $addr = $_SERVER['HTTP_CLIENT_IP'];
            } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
               $addr = $_SERVER['HTTP_X_FORWARDED_FOR'];
            } else {
               $addr = $_SERVER['REMOTE_ADDR'];
            }
            return $addr;
        }
      ?>

    </body>
    </html>
    ```

    Where:
    * `$secret`: Secret key created when configuring the CDN resource.
    * `$domain_name`: Domain name of the created CDN resource, e.g., `cdn.example.com`.
    * `$path`: [Key of the object](../../../storage/concepts/object.md#key) in the [source](../../concepts/origins.md) bucket, e.g., `/content.jpg`. It must contain `/`.
       The website will generate a signed link to access this object via the CDN resource.


## Test secure access to files {#check}

To test the generator of signed links to the secure CDN resource:

1. In your browser, go to the website you created, e.g., `https://example.com`.
1. Click the link that was generated.

    If everything works as it should, you will see the image hosted on the secure CDN resource.

    {% note info %}

    An active VPN may interfere with the signed link generator's operation. For the website to work correctly, disable your VPN.

    {% endnote %}

1. Open the generated link on another device that uses another IP address to access the internet, e.g., a smartphone.

    Access to content will be denied.

1. Try opening the link on the first device after the five-minute timeout expires.

    Access to content will be denied.

You have configured secure access to your content.

When generating links, you can also [specify](../../operations/resources/enable-secure-token.md) a trusted IP address, e.g., the one used for internet access in your corporate network. Thus you will restrict access to your content from outside your company’s network infrastructure.


## How to delete the resources you created {#clear-out}

To stop paying for the resources you created:

1. [Delete](../../operations/resources/delete-resource.md) the CDN resource, then [delete](../../operations/origin-groups/delete-group.md) the origin group.
1. [Delete](../../../storage/operations/objects/delete.md) the objects you created in the bucket, then [delete](../../../storage/operations/buckets/delete.md) the bucket itself.
1. [Delete](../../../compute/operations/vm-control/vm-delete.md) the VM you created.
1. [Delete](../../../dns/operations/zone-delete.md) the domain zone you created.
1. [Delete](../../../certificate-manager/operations/managed/cert-delete.md) the TLS certificate you created.
1. [Delete](../../../vpc/operations/security-group-delete.md) the security group you created, then [delete](../../../vpc/operations/subnet-delete.md) the subnet you created, and finally, [delete](../../../vpc/operations/network-delete.md) the network you created.

#### Useful links {#see-also}

* [Providing secure access to content in Cloud CDN through Terraform](terraform.md)