Skip to content

Commit

Permalink
fix(tls_mutual_authentication): update activation after mtls creation (
Browse files Browse the repository at this point in the history
…#829)

* fix(tls_mutual_authentication): update activation after mtls creation

* build: bump go-fastly to v9.2.1

* doc(tls_mutual_authentication): clarify include attribute

* docs(tls_mutual_authentication): add example

* test: fastly_tls_mutual_authentication

* fix(tls_mutual_authentication): allow null for mTLS ID

* doc(tls_mutual_authentication): make activation_id optional

* build: bump go-fastly to v9.2.2

* fix(tls_mutual_authentication): support multiple TLS Activations

* fix(tls_mutual_authentication): unset mTLS on old TLS Activations

* doc(tls_mutual_authentication): remove redundant annotations

* doc(tls_mutual_authentication): replace lets-encrypt with certainly

* fix(mutual_authentication): avoid accidental plan change by using runtime value for subscription certificate_id
  • Loading branch information
Integralist authored Apr 15, 2024
1 parent 0e020c2 commit 1ac8dc0
Show file tree
Hide file tree
Showing 17 changed files with 619 additions and 45 deletions.
1 change: 1 addition & 0 deletions docs/data-sources/tls_subscription.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ data "fastly_tls_subscription" "example" {

### Read-Only

- `certificate_ids` (Set of String) List of certificate IDs associated with the Subscription.
- `common_name` (String) The common name associated with the subscription generated by Fastly TLS.
- `created_at` (String) Timestamp (GMT) when subscription was created.
- `state` (String) The current state of the subscription. The list of possible states are: `pending`, `processing`, `issued`, and `renewing`.
Expand Down
224 changes: 218 additions & 6 deletions docs/resources/tls_mutual_authentication.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,227 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "fastly_tls_mutual_authentication Resource - terraform-provider-fastly"
subcategory: ""
layout: "fastly"
page_title: "Fastly: tls_mutual_authentication"
sidebar_current: "docs-fastly-resource-tls_mutual_authentication"
description: |-
Allows for client-to-server authentication using client-side X.509 authentication.
---

# fastly_tls_mutual_authentication (Resource)
# fastly_tls_mutual_authentication

The Mutual TLS API allows for client-to-server authentication using client-side X.509 authentication.

The main Mutual Authentication object represents the certificate bundle and other configurations which support Mutual TLS for your domains.

Mutual TLS can be added to existing TLS activations to allow for client-to-server authentication. In order to use mutual TLS, you must already have active server-side TLS using either custom certificates or an enabled Fastly-managed subscription.

The examples below demonstrate how to use Mutual Authentication along with a TLS Subscription. Refer to the `fastly_tls_subscription` resource documentation for a deeper explanation of that code.

## Example: Single Activation

The following example sets up a TLS Subscription for `www.example.com` and then adds Mutual Authentication.

```terraform
terraform {
required_providers {
dnsimple = {
source = "dnsimple/dnsimple"
version = "1.5.0"
}
fastly = {
source = "fastly/fastly"
version = "5.7.2"
}
}
}
variable "dnsimple_token" {
type = string
}
variable "dnsimple_account" {
type = string
}
provider "dnsimple" {
account = var.dnsimple_account
token = var.dnsimple_token
}
variable "zone" {
type = string
default = "example.com"
}
resource "fastly_service_vcl" "example" {
name = "example"
domain {
name = "www.${var.zone}"
}
backend {
address = "httpbin.org"
name = "httpbin"
}
force_destroy = true
}
resource "fastly_tls_subscription" "www" {
domains = [for domain in fastly_service_vcl.example.domain : domain.name if domain.name == "www.${var.zone}"]
certificate_authority = "certainly"
}
resource "dnsimple_zone_record" "www_acme_challenge" {
name = "_acme-challenge.www"
ttl = "60"
type = "CNAME"
value = one([for obj in fastly_tls_subscription.www.managed_dns_challenges : obj.record_value if obj.record_name == "_acme-challenge.www.${var.zone}"])
zone_name = var.zone
}
resource "fastly_tls_subscription_validation" "www" {
subscription_id = fastly_tls_subscription.www.id
depends_on = [dnsimple_zone_record.www_acme_challenge]
}
data "fastly_tls_configuration" "default" {
default = true
depends_on = [fastly_tls_subscription_validation.www]
}
resource "dnsimple_zone_record" "www" {
name = "www"
ttl = "60"
type = "CNAME"
value = one([for record in data.fastly_tls_configuration.default.dns_records : record.record_value if record.record_type == "CNAME"])
zone_name = var.zone
}
data "fastly_tls_activation" "www" {
domain = "www.example.com"
depends_on = [dnsimple_zone_record.www]
}
resource "fastly_tls_mutual_authentication" "www" {
activation_ids = [data.fastly_tls_activation.www.id]
cert_bundle = "-----BEGIN CERTIFICATE-----\n<REDACTED>\n-----END CERTIFICATE-----"
enforced = true
}
```

## Example: Multiple Activations

The following example sets up a TLS Subscription for `foo.example.com` and `bar.example.com` and then adds Mutual Authentication to each TLS Activation.

```terraform
terraform {
required_providers {
dnsimple = {
source = "dnsimple/dnsimple"
version = "1.5.0"
}
fastly = {
source = "fastly/fastly"
version = "5.7.2"
}
}
}
variable "dnsimple_token" {
type = string
}
variable "dnsimple_account" {
type = string
}
provider "dnsimple" {
account = var.dnsimple_account
token = var.dnsimple_token
}
variable "zone" {
type = string
default = "example.com"
}
resource "fastly_service_vcl" "example" {
name = "example"
domain {
name = "foo.${var.zone}"
}
domain {
name = "bar.${var.zone}"
}
backend {
address = "httpbin.org"
name = "httpbin"
}
force_destroy = true
}
resource "fastly_tls_subscription" "example" {
domains = [for domain in fastly_service_vcl.example.domain : domain.name]
certificate_authority = "certainly"
}
resource "dnsimple_zone_record" "example_acme_challenge" {
for_each = {
for domain in fastly_tls_subscription.example.domains : domain => one([
for obj in fastly_tls_subscription.example.managed_dns_challenges : obj if obj.record_name == "_acme-challenge.${domain}"
])
}
name = each.value.record_name
ttl = "60"
type = each.value.record_type
value = each.value.record_value
zone_name = var.zone
}
resource "fastly_tls_subscription_validation" "example" {
subscription_id = fastly_tls_subscription.example.id
depends_on = [dnsimple_zone_record.example_acme_challenge]
}
data "fastly_tls_configuration" "default" {
default = true
depends_on = [fastly_tls_subscription_validation.example]
}
resource "dnsimple_zone_record" "foo" {
name = "foo"
ttl = "60"
type = "CNAME"
value = one([for record in data.fastly_tls_configuration.default.dns_records : record.record_value if record.record_type == "CNAME"])
zone_name = var.zone
}
resource "dnsimple_zone_record" "bar" {
name = "bar"
ttl = "60"
type = "CNAME"
value = one([for record in data.fastly_tls_configuration.default.dns_records : record.record_value if record.record_type == "CNAME"])
zone_name = var.zone
}
# IMPORTANT: The subscription's certificate_id attribute is initially empty.
# So we can't reference the certificate_id attribute directly (not until a state refresh).
# This means we need to use the subscription data source instead.
# We need this data source to wait for the subscription process to complete.
# Once complete we'll have a Certificate ID we can reference as input to the `fastly_tls_activation_ids` data source.
data "fastly_tls_subscription" "example" {
id = fastly_tls_subscription.example.id
depends_on = [fastly_tls_subscription_validation.example]
}
data "fastly_tls_activation_ids" "example" {
certificate_id = one(data.fastly_tls_subscription.example.certificate_ids)
}
resource "fastly_tls_mutual_authentication" "example" {
activation_ids = data.fastly_tls_activation_ids.example.ids
cert_bundle = "-----BEGIN CERTIFICATE-----\n<REDACTED>\n-----END CERTIFICATE-----"
enforced = true
}
```

<!-- schema generated by tfplugindocs -->
## Schema
Expand All @@ -21,8 +232,9 @@ description: |-

### Optional

- `activation_ids` (Set of String) List of TLS Activation IDs
- `enforced` (Boolean) Determines whether Mutual TLS will fail closed (enforced) or fail open. A true value will require a successful Mutual TLS handshake for the connection to continue and will fail closed if unsuccessful. A false value will fail open and allow the connection to proceed (if this attribute is not set we default to `false`).
- `include` (String) Comma-separated list of related objects to include (e.g. `tls_activations` will provide you with the TLS domain names that are related to your Mutual TLS authentication).
- `include` (String) A comma-separated list used by the Terraform provider during a state refresh to return more data related to your mutual authentication from the Fastly API (permitted values: `tls_activations`).
- `name` (String) A custom name for your mutual authentication. If name is not supplied we will auto-generate one.

### Read-Only
Expand Down
84 changes: 84 additions & 0 deletions examples/resources/tls_mutual_authentication_basic_usage.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
terraform {
required_providers {
dnsimple = {
source = "dnsimple/dnsimple"
version = "1.5.0"
}
fastly = {
source = "fastly/fastly"
version = "5.7.2"
}
}
}

variable "dnsimple_token" {
type = string
}

variable "dnsimple_account" {
type = string
}

provider "dnsimple" {
account = var.dnsimple_account
token = var.dnsimple_token
}

variable "zone" {
type = string
default = "example.com"
}

resource "fastly_service_vcl" "example" {
name = "example"
domain {
name = "www.${var.zone}"
}
backend {
address = "httpbin.org"
name = "httpbin"
}
force_destroy = true
}

resource "fastly_tls_subscription" "www" {
domains = [for domain in fastly_service_vcl.example.domain : domain.name if domain.name == "www.${var.zone}"]
certificate_authority = "certainly"
}

resource "dnsimple_zone_record" "www_acme_challenge" {
name = "_acme-challenge.www"
ttl = "60"
type = "CNAME"
value = one([for obj in fastly_tls_subscription.www.managed_dns_challenges : obj.record_value if obj.record_name == "_acme-challenge.www.${var.zone}"])
zone_name = var.zone
}

resource "fastly_tls_subscription_validation" "www" {
subscription_id = fastly_tls_subscription.www.id
depends_on = [dnsimple_zone_record.www_acme_challenge]
}

data "fastly_tls_configuration" "default" {
default = true
depends_on = [fastly_tls_subscription_validation.www]
}

resource "dnsimple_zone_record" "www" {
name = "www"
ttl = "60"
type = "CNAME"
value = one([for record in data.fastly_tls_configuration.default.dns_records : record.record_value if record.record_type == "CNAME"])
zone_name = var.zone
}

data "fastly_tls_activation" "www" {
domain = "www.example.com"
depends_on = [dnsimple_zone_record.www]
}

resource "fastly_tls_mutual_authentication" "www" {
activation_ids = [data.fastly_tls_activation.www.id]
cert_bundle = "-----BEGIN CERTIFICATE-----\n<REDACTED>\n-----END CERTIFICATE-----"
enforced = true
}
Loading

0 comments on commit 1ac8dc0

Please sign in to comment.