diff --git a/Documentation/variables/config.md b/Documentation/variables/config.md index 87891babf6..07885f8989 100644 --- a/Documentation/variables/config.md +++ b/Documentation/variables/config.md @@ -30,6 +30,9 @@ This document gives an overview of variables used in all platforms of the Tecton | tectonic_etcd_tls_enabled | (optional) If set to `true`, TLS secure communication for self-provisioned etcd. will be used.

Note: If `tectonic_experimental` is set to `true` this variable has no effect, because the experimental self-hosted etcd always uses TLS. | string | `true` | | tectonic_experimental | If set to true, experimental Tectonic assets are being deployed. | string | `false` | | tectonic_image_re | (internal) Regular expression used to extract repo and tag components | string | `/^([^/]+/[^/]+/[^/]+):(.*)$/` | +| tectonic_ingress_ca_cert_pem | (optional) The content of the PEM-encoded CA certificate that was used to sign the Tectonic Console's server certificate. If left blank, a CA certificate will be automatically generated. | string | `` | +| tectonic_ingress_cert_pem | (optional) The content of the PEM-encoded certificate for the Tectonic Console that was signed by `tectonic_ingress_ca_cert_pem`. This field is mandatory if `tectonic_ingress_ca_cert_pem` is set. | string | `` | +| tectonic_ingress_key_pem | (optional) The content of the PEM-encoded certificate key for the Tectonic Console certificate. This field is mandatory if `tectonic_ingress_ca_cert_pem` is set. | string | `` | | tectonic_license_path | The path to the tectonic licence file. You can download the Tectonic license file from your Account overview page at [1].

[1] https://account.coreos.com/overview

Note: This field MUST be set manually prior to creating the cluster unless `tectonic_vanilla_k8s` is set to `true`. | string | `` | | tectonic_master_count | The number of master nodes to be created. This applies only to cloud platforms. | string | `1` | | tectonic_pull_secret_path | The path the pull secret file in JSON format. This is known to be a "Docker pull secret" as produced by the docker login [1] command. A sample JSON content is shown in [2]. You can download the pull secret from your Account overview page at [3].

[1] https://docs.docker.com/engine/reference/commandline/login/

[2] https://coreos.com/os/docs/latest/registry-authentication.html#manual-registry-auth-setup

[3] https://account.coreos.com/overview

Note: This field MUST be set manually prior to creating the cluster unless `tectonic_vanilla_k8s` is set to `true`. | string | `` | diff --git a/config.tf b/config.tf index 16dabfa86d..e9679249a5 100644 --- a/config.tf +++ b/config.tf @@ -333,6 +333,36 @@ This field is mandatory if `tectonic_ca_cert` is set. EOF } +variable "tectonic_ingress_ca_cert_pem" { + type = "string" + default = "" + + description = < { ret.variables.tectonic_ca_cert = cc[CA_CERTIFICATE]; ret.variables.tectonic_ca_key = cc[CA_PRIVATE_KEY]; ret.variables.tectonic_ca_key_alg = keyToAlg(cc[CA_PRIVATE_KEY]); + } else if (cc[CA_TYPE] === 'ca-signed') { + ret.variables.tectonic_ingress_ca_cert_pem = cc[INGRESS_CA_CERTIFICATE]; + ret.variables.tectonic_ingress_cert_pem = cc[INGRESS_CERTIFICATE]; + ret.variables.tectonic_ingress_key_pem = cc[INGRESS_PRIVATE_KEY]; } + return ret; }; @@ -345,6 +356,10 @@ export const toBaremetal_TF = (cc, FORMS, opts = {}) => { ret.variables.tectonic_ca_cert = cc[CA_CERTIFICATE]; ret.variables.tectonic_ca_key = cc[CA_PRIVATE_KEY]; ret.variables.tectonic_ca_key_alg = keyToAlg(cc[CA_PRIVATE_KEY]); + } else if (cc[CA_TYPE] === 'ca-signed') { + ret.variables.tectonic_ingress_ca_cert_pem = cc[INGRESS_CA_CERTIFICATE]; + ret.variables.tectonic_ingress_cert_pem = cc[INGRESS_CERTIFICATE]; + ret.variables.tectonic_ingress_key_pem = cc[INGRESS_PRIVATE_KEY]; } return ret; diff --git a/installer/frontend/components/certificate-authority.jsx b/installer/frontend/components/certificate-authority.jsx index 070e2b814e..514a75c2b1 100644 --- a/installer/frontend/components/certificate-authority.jsx +++ b/installer/frontend/components/certificate-authority.jsx @@ -3,7 +3,7 @@ import { connect } from 'react-redux'; import { configActionTypes } from '../actions'; import { validate } from '../validate'; -import { CA_TYPE, CA_CERTIFICATE, CA_PRIVATE_KEY } from '../cluster-config'; +import { CA_TYPE, CA_CERTIFICATE, CA_PRIVATE_KEY, INGRESS_CERTIFICATE, INGRESS_PRIVATE_KEY, INGRESS_CA_CERTIFICATE } from '../cluster-config'; import { WithClusterConfig, CertArea, PrivateKeyArea } from './ui'; export const CertificateAuthority = connect( @@ -87,6 +87,55 @@ export const CertificateAuthority = connect( } +
+
+ +

Your certificate will be used by the Tectonic Console.

+
+
+ { + caType === 'ca-signed' &&
+
+
+ + + +
+
+ +
+
+ + + +
+
+ +
+
+ + + +
+
+
+ } +
+
@@ -97,6 +146,13 @@ CertificateAuthority.canNavigateForward = ({clusterConfig}) => { return true; } - return (!validate.certificate(clusterConfig[CA_CERTIFICATE]) && - !validate.privateKey(clusterConfig[CA_PRIVATE_KEY])); + + if (clusterConfig[CA_TYPE] === 'owned') { + return (!validate.certificate(clusterConfig[CA_CERTIFICATE]) && + !validate.privateKey(clusterConfig[CA_PRIVATE_KEY])); + } + + return (!validate.certificate(clusterConfig[INGRESS_CERTIFICATE]) && + !validate.certificate(clusterConfig[INGRESS_CA_CERTIFICATE]) && + !validate.privateKey(clusterConfig[INGRESS_PRIVATE_KEY])); }; diff --git a/modules/tectonic/assets.tf b/modules/tectonic/assets.tf index bb1da97334..84bbc7bbd4 100644 --- a/modules/tectonic/assets.tf +++ b/modules/tectonic/assets.tf @@ -69,8 +69,9 @@ resource "template_dir" "tectonic" { prometheus_callback = "https://${var.base_address}/prometheus/auth/callback" ingress_kind = "${var.ingress_kind}" - ingress_tls_cert = "${base64encode(tls_locally_signed_cert.ingress.cert_pem)}" - ingress_tls_key = "${base64encode(tls_private_key.ingress.private_key_pem)}" + ingress_ca_cert = "${base64encode(var.ingress_ca_cert_pem)}" + ingress_tls_cert = "${base64encode(var.ingress_cert_pem)}" + ingress_tls_key = "${base64encode(var.ingress_key_pem)}" identity_server_tls_cert = "${base64encode(tls_locally_signed_cert.identity_server.cert_pem)}" identity_server_tls_key = "${base64encode(tls_private_key.identity_server.private_key_pem)}" diff --git a/modules/tectonic/crypto.tf b/modules/tectonic/crypto.tf index 84a6cbcd23..5169e39a61 100644 --- a/modules/tectonic/crypto.tf +++ b/modules/tectonic/crypto.tf @@ -16,45 +16,6 @@ resource "random_id" "tectonic_monitoring_auth_cookie_secret" { byte_length = 16 } -# Ingress' server certificate - -resource "tls_private_key" "ingress" { - algorithm = "RSA" - rsa_bits = "2048" -} - -resource "tls_cert_request" "ingress" { - key_algorithm = "${tls_private_key.ingress.algorithm}" - private_key_pem = "${tls_private_key.ingress.private_key_pem}" - - subject { - common_name = "${element(split(":", var.base_address), 0)}" - } - - # subject commonName is deprecated per RFC2818 in favor of - # subjectAltName - dns_names = [ - "${element(split(":", var.base_address), 0)}", - ] -} - -resource "tls_locally_signed_cert" "ingress" { - cert_request_pem = "${tls_cert_request.ingress.cert_request_pem}" - - ca_key_algorithm = "${var.ca_key_alg}" - ca_private_key_pem = "${var.ca_key}" - ca_cert_pem = "${var.ca_cert}" - - validity_period_hours = 8760 - - allowed_uses = [ - "key_encipherment", - "digital_signature", - "server_auth", - "client_auth", - ] -} - # Identity's gRPC server/client certificates resource "tls_private_key" "identity_server" { diff --git a/modules/tectonic/resources/manifests/console/deployment.yaml b/modules/tectonic/resources/manifests/console/deployment.yaml index 2296a0007c..d84dfe0ff2 100644 --- a/modules/tectonic/resources/manifests/console/deployment.yaml +++ b/modules/tectonic/resources/manifests/console/deployment.yaml @@ -98,6 +98,8 @@ spec: value: /etc/tectonic-ca-cert-secret/ca-cert - name: BRIDGE_LICENSE_FILE value: /etc/tectonic/licenses/license + - name: BRIDGE_DEX_CLIENT_CA_FILE + value: /etc/tectonic-identity-grpc-client-secret/ca-cert - name: BRIDGE_DEX_CLIENT_CERT_FILE value: /etc/tectonic-identity-grpc-client-secret/tls-cert - name: BRIDGE_DEX_CLIENT_KEY_FILE diff --git a/modules/tectonic/resources/manifests/secrets/ca-cert.yaml b/modules/tectonic/resources/manifests/secrets/ca-cert.yaml index d9c885e373..88f71093b8 100644 --- a/modules/tectonic/resources/manifests/secrets/ca-cert.yaml +++ b/modules/tectonic/resources/manifests/secrets/ca-cert.yaml @@ -5,4 +5,4 @@ metadata: namespace: tectonic-system type: Opaque data: - ca-cert: ${ca_cert} \ No newline at end of file + ca-cert: ${ingress_ca_cert} diff --git a/modules/tectonic/variables.tf b/modules/tectonic/variables.tf index f1a0b8fb05..ae7d442b58 100644 --- a/modules/tectonic/variables.tf +++ b/modules/tectonic/variables.tf @@ -129,3 +129,15 @@ EOF type = "string" } + +variable "ingress_ca_cert_pem" { + type = "string" +} + +variable "ingress_cert_pem" { + type = "string" +} + +variable "ingress_key_pem" { + type = "string" +} diff --git a/modules/tls/ingress/main.tf b/modules/tls/ingress/main.tf new file mode 100644 index 0000000000..8bc3985c82 --- /dev/null +++ b/modules/tls/ingress/main.tf @@ -0,0 +1,16 @@ +module "ingress_certs_self_signed" { + source = "./self-signed" + + base_address = "${var.base_address}" + ca_cert_pem = "${var.ca_cert_pem}" + ca_key_pem = "${var.ca_key_pem}" + ca_key_alg = "${var.ca_key_alg}" +} + +module "ingress_certs_user_provided" { + source = "./user-provided" + + ca_cert_pem = "${var.ingress_ca_cert_pem}" + cert_pem = "${var.ingress_cert_pem}" + key_pem = "${var.ingress_key_pem}" +} diff --git a/modules/tls/ingress/outputs.tf b/modules/tls/ingress/outputs.tf new file mode 100644 index 0000000000..ec979bcf2b --- /dev/null +++ b/modules/tls/ingress/outputs.tf @@ -0,0 +1,11 @@ +output "ca_cert_pem" { + value = "${var.ingress_ca_cert_pem == "" ? module.ingress_certs_self_signed.ca_cert_pem : module.ingress_certs_user_provided.ca_cert_pem}" +} + +output "cert_pem" { + value = "${var.ingress_ca_cert_pem == "" ? module.ingress_certs_self_signed.cert_pem : module.ingress_certs_user_provided.cert_pem}" +} + +output "key_pem" { + value = "${var.ingress_ca_cert_pem == "" ? module.ingress_certs_self_signed.key_pem : module.ingress_certs_user_provided.key_pem}" +} diff --git a/modules/tls/ingress/self-signed/main.tf b/modules/tls/ingress/self-signed/main.tf new file mode 100644 index 0000000000..d6f30f315a --- /dev/null +++ b/modules/tls/ingress/self-signed/main.tf @@ -0,0 +1,36 @@ +resource "tls_private_key" "ingress" { + algorithm = "RSA" + rsa_bits = "2048" +} + +resource "tls_cert_request" "ingress" { + key_algorithm = "${tls_private_key.ingress.algorithm}" + private_key_pem = "${tls_private_key.ingress.private_key_pem}" + + subject { + common_name = "${element(split(":", var.base_address), 0)}" + } + + # subject commonName is deprecated per RFC2818 in favor of + # subjectAltName + dns_names = [ + "${element(split(":", var.base_address), 0)}", + ] +} + +resource "tls_locally_signed_cert" "ingress" { + cert_request_pem = "${tls_cert_request.ingress.cert_request_pem}" + + ca_key_algorithm = "${var.ca_key_alg}" + ca_private_key_pem = "${var.ca_key_pem}" + ca_cert_pem = "${var.ca_cert_pem}" + + validity_period_hours = 8760 + + allowed_uses = [ + "key_encipherment", + "digital_signature", + "server_auth", + "client_auth", + ] +} diff --git a/modules/tls/ingress/self-signed/outputs.tf b/modules/tls/ingress/self-signed/outputs.tf new file mode 100644 index 0000000000..c730834756 --- /dev/null +++ b/modules/tls/ingress/self-signed/outputs.tf @@ -0,0 +1,11 @@ +output "ca_cert_pem" { + value = "${var.ca_cert_pem}" +} + +output "key_pem" { + value = "${tls_private_key.ingress.private_key_pem}" +} + +output "cert_pem" { + value = "${tls_locally_signed_cert.ingress.cert_pem}" +} diff --git a/modules/tls/ingress/self-signed/variables.tf b/modules/tls/ingress/self-signed/variables.tf new file mode 100644 index 0000000000..6122b07193 --- /dev/null +++ b/modules/tls/ingress/self-signed/variables.tf @@ -0,0 +1,15 @@ +variable "base_address" { + type = "string" +} + +variable "ca_cert_pem" { + type = "string" +} + +variable "ca_key_pem" { + type = "string" +} + +variable "ca_key_alg" { + type = "string" +} diff --git a/modules/tls/ingress/user-provided/outputs.tf b/modules/tls/ingress/user-provided/outputs.tf new file mode 100644 index 0000000000..29339deaf0 --- /dev/null +++ b/modules/tls/ingress/user-provided/outputs.tf @@ -0,0 +1,11 @@ +output "ca_cert_pem" { + value = "${var.ca_cert_pem}" +} + +output "cert_pem" { + value = "${var.cert_pem}" +} + +output "key_pem" { + value = "${var.key_pem}" +} diff --git a/modules/tls/ingress/user-provided/variables.tf b/modules/tls/ingress/user-provided/variables.tf new file mode 100644 index 0000000000..13f5980a8f --- /dev/null +++ b/modules/tls/ingress/user-provided/variables.tf @@ -0,0 +1,11 @@ +variable "ca_cert_pem" { + type = "string" +} + +variable "cert_pem" { + type = "string" +} + +variable "key_pem" { + type = "string" +} diff --git a/modules/tls/ingress/variables.tf b/modules/tls/ingress/variables.tf new file mode 100644 index 0000000000..3e5c4bfa66 --- /dev/null +++ b/modules/tls/ingress/variables.tf @@ -0,0 +1,27 @@ +variable "base_address" { + type = "string" +} + +variable "ca_cert_pem" { + type = "string" +} + +variable "ca_key_pem" { + type = "string" +} + +variable "ca_key_alg" { + type = "string" +} + +variable "ingress_ca_cert_pem" { + type = "string" +} + +variable "ingress_cert_pem" { + type = "string" +} + +variable "ingress_key_pem" { + type = "string" +} diff --git a/platforms/aws/tectonic.tf b/platforms/aws/tectonic.tf index 76bc3f97fa..3d08856b75 100644 --- a/platforms/aws/tectonic.tf +++ b/platforms/aws/tectonic.tf @@ -1,3 +1,16 @@ +module "ingress_certs" { + source = "../../modules/tls/ingress" + + base_address = "${var.tectonic_aws_private_endpoints ? module.masters.ingress_internal_fqdn : module.masters.ingress_external_fqdn}" + ca_cert_pem = "${module.bootkube.ca_cert}" + ca_key_pem = "${module.bootkube.ca_key}" + ca_key_alg = "${module.bootkube.ca_key_alg}" + + ingress_ca_cert_pem = "${var.tectonic_ingress_ca_cert_pem}" + ingress_cert_pem = "${var.tectonic_ingress_cert_pem}" + ingress_key_pem = "${var.tectonic_ingress_key_pem}" +} + module "bootkube" { source = "../../modules/bootkube" cloud_provider = "aws" @@ -96,6 +109,10 @@ module "tectonic" { ca_key_alg = "${module.bootkube.ca_key_alg}" ca_key = "${module.bootkube.ca_key}" + ingress_ca_cert_pem = "${module.ingress_certs.ca_cert_pem}" + ingress_cert_pem = "${module.ingress_certs.cert_pem}" + ingress_key_pem = "${module.ingress_certs.key_pem}" + console_client_id = "tectonic-console" kubectl_client_id = "tectonic-kubectl" ingress_kind = "NodePort" diff --git a/platforms/azure/tectonic.tf b/platforms/azure/tectonic.tf index d2a3318b0e..6e74b88464 100644 --- a/platforms/azure/tectonic.tf +++ b/platforms/azure/tectonic.tf @@ -1,3 +1,16 @@ +module "ingress_certs" { + source = "../../modules/tls/ingress" + + base_address = "${module.vnet.ingress_fqdn}" + ca_cert_pem = "${module.bootkube.ca_cert}" + ca_key_pem = "${module.bootkube.ca_key}" + ca_key_alg = "${module.bootkube.ca_key_alg}" + + ingress_ca_cert_pem = "${var.tectonic_ingress_ca_cert_pem}" + ingress_cert_pem = "${var.tectonic_ingress_cert_pem}" + ingress_key_pem = "${var.tectonic_ingress_key_pem}" +} + module "bootkube" { source = "../../modules/bootkube" @@ -67,6 +80,10 @@ module "tectonic" { ca_key_alg = "${module.bootkube.ca_key_alg}" ca_key = "${module.bootkube.ca_key}" + ingress_ca_cert_pem = "${module.ingress_certs.ca_cert_pem}" + ingress_cert_pem = "${module.ingress_certs.cert_pem}" + ingress_key_pem = "${module.ingress_certs.key_pem}" + console_client_id = "tectonic-console" kubectl_client_id = "tectonic-kubectl" ingress_kind = "NodePort" diff --git a/platforms/metal/tectonic.tf b/platforms/metal/tectonic.tf index 49e3366d77..158641b79b 100644 --- a/platforms/metal/tectonic.tf +++ b/platforms/metal/tectonic.tf @@ -1,3 +1,16 @@ +module "ingress_certs" { + source = "../../modules/tls/ingress" + + base_address = "${var.tectonic_metal_ingress_domain}" + ca_cert_pem = "${module.bootkube.ca_cert}" + ca_key_pem = "${module.bootkube.ca_key}" + ca_key_alg = "${module.bootkube.ca_key_alg}" + + ingress_ca_cert_pem = "${var.tectonic_ingress_ca_cert_pem}" + ingress_cert_pem = "${var.tectonic_ingress_cert_pem}" + ingress_key_pem = "${var.tectonic_ingress_key_pem}" +} + module "bootkube" { source = "../../modules/bootkube" cloud_provider = "" @@ -75,6 +88,10 @@ module "tectonic" { ca_key_alg = "${module.bootkube.ca_key_alg}" ca_key = "${module.bootkube.ca_key}" + ingress_ca_cert_pem = "${module.ingress_certs.ca_cert_pem}" + ingress_cert_pem = "${module.ingress_certs.cert_pem}" + ingress_key_pem = "${module.ingress_certs.key_pem}" + console_client_id = "tectonic-console" kubectl_client_id = "tectonic-kubectl" ingress_kind = "HostPort" diff --git a/platforms/openstack/neutron/main.tf b/platforms/openstack/neutron/main.tf index a44df296e5..73d0ff9271 100644 --- a/platforms/openstack/neutron/main.tf +++ b/platforms/openstack/neutron/main.tf @@ -1,3 +1,16 @@ +module "ingress_certs" { + source = "../../modules/tls/ingress" + + base_address = "${var.tectonic_cluster_name}.${var.tectonic_base_domain}" + ca_cert_pem = "${module.bootkube.ca_cert}" + ca_key_pem = "${module.bootkube.ca_key}" + ca_key_alg = "${module.bootkube.ca_key_alg}" + + ingress_ca_cert_pem = "${var.tectonic_ingress_ca_cert_pem}" + ingress_cert_pem = "${var.tectonic_ingress_cert_pem}" + ingress_key_pem = "${var.tectonic_ingress_key_pem}" +} + module "bootkube" { source = "../../../modules/bootkube" cloud_provider = "" @@ -74,6 +87,10 @@ module "tectonic" { ca_key_alg = "${module.bootkube.ca_key_alg}" ca_key = "${module.bootkube.ca_key}" + ingress_ca_cert_pem = "${module.ingress_certs.ca_cert_pem}" + ingress_cert_pem = "${module.ingress_certs.cert_pem}" + ingress_key_pem = "${module.ingress_certs.key_pem}" + console_client_id = "tectonic-console" kubectl_client_id = "tectonic-kubectl" ingress_kind = "HostPort" diff --git a/platforms/vmware/tectonic.tf b/platforms/vmware/tectonic.tf index 945b0ed762..0ee8d1e310 100644 --- a/platforms/vmware/tectonic.tf +++ b/platforms/vmware/tectonic.tf @@ -1,3 +1,16 @@ +module "ingress_certs" { + source = "../../modules/tls/ingress" + + base_address = "${var.tectonic_vmware_ingress_domain}" + ca_cert_pem = "${module.bootkube.ca_cert}" + ca_key_pem = "${module.bootkube.ca_key}" + ca_key_alg = "${module.bootkube.ca_key_alg}" + + ingress_ca_cert_pem = "${var.tectonic_ingress_ca_cert_pem}" + ingress_cert_pem = "${var.tectonic_ingress_cert_pem}" + ingress_key_pem = "${var.tectonic_ingress_key_pem}" +} + module "bootkube" { source = "../../modules/bootkube" cloud_provider = "" @@ -77,6 +90,10 @@ module "tectonic" { ca_key_alg = "${module.bootkube.ca_key_alg}" ca_key = "${module.bootkube.ca_key}" + ingress_ca_cert_pem = "${module.ingress_certs.ca_cert_pem}" + ingress_cert_pem = "${module.ingress_certs.cert_pem}" + ingress_key_pem = "${module.ingress_certs.key_pem}" + console_client_id = "tectonic-console" kubectl_client_id = "tectonic-kubectl" ingress_kind = "HostPort"