diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml index 9a3ff5e845..f01f8c145c 100644 --- a/.github/workflows/develop.yml +++ b/.github/workflows/develop.yml @@ -763,6 +763,7 @@ jobs: GT_MINIO_ACCESS_KEY: superpower_password GT_MINIO_REGION: us-west-2 GT_MINIO_ENDPOINT_URL: http://127.0.0.1:9000 + GT_ETCD_TLS_ENDPOINTS: https://127.0.0.1:2378 GT_ETCD_ENDPOINTS: http://127.0.0.1:2379 GT_POSTGRES_ENDPOINTS: postgres://greptimedb:admin@127.0.0.1:5432/postgres GT_MYSQL_ENDPOINTS: mysql://greptimedb:admin@127.0.0.1:3306/mysql @@ -815,6 +816,7 @@ jobs: GT_MINIO_ACCESS_KEY: superpower_password GT_MINIO_REGION: us-west-2 GT_MINIO_ENDPOINT_URL: http://127.0.0.1:9000 + GT_ETCD_TLS_ENDPOINTS: https://127.0.0.1:2378 GT_ETCD_ENDPOINTS: http://127.0.0.1:2379 GT_POSTGRES_ENDPOINTS: postgres://greptimedb:admin@127.0.0.1:5432/postgres GT_MYSQL_ENDPOINTS: mysql://greptimedb:admin@127.0.0.1:3306/mysql diff --git a/Cargo.lock b/Cargo.lock index c86a7f77a2..37b8bb7736 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13486,6 +13486,7 @@ dependencies = [ "percent-encoding", "pin-project", "prost 0.13.5", + "rustls-native-certs 0.8.1", "socket2 0.5.10", "tokio", "tokio-rustls", diff --git a/Cargo.toml b/Cargo.toml index a2e8d368e4..47748c4e40 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -138,7 +138,10 @@ deadpool-postgres = "0.14" derive_builder = "0.20" dotenv = "0.15" either = "1.15" -etcd-client = { git = "https://github.com/GreptimeTeam/etcd-client", rev = "f62df834f0cffda355eba96691fe1a9a332b75a7" } +etcd-client = { git = "https://github.com/GreptimeTeam/etcd-client", rev = "f62df834f0cffda355eba96691fe1a9a332b75a7", features = [ + "tls", + "tls-roots", +] } fst = "0.4.7" futures = "0.3" futures-util = "0.3" diff --git a/config/config.md b/config/config.md index 7b3f4745b3..de44c6de89 100644 --- a/config/config.md +++ b/config/config.md @@ -344,7 +344,7 @@ | `runtime` | -- | -- | The runtime options. | | `runtime.global_rt_size` | Integer | `8` | The number of threads to execute the runtime for global read operations. | | `runtime.compact_rt_size` | Integer | `4` | The number of threads to execute the runtime for global write operations. | -| `backend_tls` | -- | -- | TLS configuration for kv store backend (only applicable for PostgreSQL/MySQL backends)
When using PostgreSQL or MySQL as metadata store, you can configure TLS here | +| `backend_tls` | -- | -- | TLS configuration for kv store backend (applicable for etcd, PostgreSQL, and MySQL backends)
When using etcd, PostgreSQL, or MySQL as metadata store, you can configure TLS here | | `backend_tls.mode` | String | `prefer` | TLS mode, refer to https://www.postgresql.org/docs/current/libpq-ssl.html
- "disable" - No TLS
- "prefer" (default) - Try TLS, fallback to plain
- "require" - Require TLS
- "verify_ca" - Require TLS and verify CA
- "verify_full" - Require TLS and verify hostname | | `backend_tls.cert_path` | String | `""` | Path to client certificate file (for client authentication)
Like "/path/to/client.crt" | | `backend_tls.key_path` | String | `""` | Path to client private key file (for client authentication)
Like "/path/to/client.key" | diff --git a/config/metasrv.example.toml b/config/metasrv.example.toml index a7f53eea49..9dc629e76f 100644 --- a/config/metasrv.example.toml +++ b/config/metasrv.example.toml @@ -65,8 +65,8 @@ node_max_idle_time = "24hours" ## The number of threads to execute the runtime for global write operations. #+ compact_rt_size = 4 -## TLS configuration for kv store backend (only applicable for PostgreSQL/MySQL backends) -## When using PostgreSQL or MySQL as metadata store, you can configure TLS here +## TLS configuration for kv store backend (applicable for etcd, PostgreSQL, and MySQL backends) +## When using etcd, PostgreSQL, or MySQL as metadata store, you can configure TLS here [backend_tls] ## TLS mode, refer to https://www.postgresql.org/docs/current/libpq-ssl.html ## - "disable" - No TLS diff --git a/docker/docker-compose/cluster-with-etcd.yaml b/docker/docker-compose/cluster-with-etcd.yaml index 4ad90f1285..34eee7f4b5 100644 --- a/docker/docker-compose/cluster-with-etcd.yaml +++ b/docker/docker-compose/cluster-with-etcd.yaml @@ -34,6 +34,48 @@ services: networks: - greptimedb + etcd-tls: + <<: *etcd_common_settings + container_name: etcd-tls + ports: + - 2378:2378 + - 2381:2381 + command: + - --name=etcd-tls + - --data-dir=/var/lib/etcd + - --initial-advertise-peer-urls=https://etcd-tls:2381 + - --listen-peer-urls=https://0.0.0.0:2381 + - --listen-client-urls=https://0.0.0.0:2378 + - --advertise-client-urls=https://etcd-tls:2378 + - --heartbeat-interval=250 + - --election-timeout=1250 + - --initial-cluster=etcd-tls=https://etcd-tls:2381 + - --initial-cluster-state=new + - --initial-cluster-token=etcd-tls-cluster + - --cert-file=/certs/server.crt + - --key-file=/certs/server-key.pem + - --peer-cert-file=/certs/server.crt + - --peer-key-file=/certs/server-key.pem + - --trusted-ca-file=/certs/ca.crt + - --peer-trusted-ca-file=/certs/ca.crt + - --client-cert-auth + - --peer-client-cert-auth + volumes: + - ./greptimedb-cluster-docker-compose/etcd-tls:/var/lib/etcd + - ./greptimedb-cluster-docker-compose/certs:/certs:ro + environment: + - ETCDCTL_API=3 + - ETCDCTL_CACERT=/certs/ca.crt + - ETCDCTL_CERT=/certs/server.crt + - ETCDCTL_KEY=/certs/server-key.pem + healthcheck: + test: [ "CMD", "etcdctl", "--endpoints=https://etcd-tls:2378", "--cacert=/certs/ca.crt", "--cert=/certs/server.crt", "--key=/certs/server-key.pem", "endpoint", "health" ] + interval: 10s + timeout: 5s + retries: 5 + networks: + - greptimedb + metasrv: image: *greptimedb_image container_name: metasrv diff --git a/scripts/generate-etcd-tls-certs.sh b/scripts/generate-etcd-tls-certs.sh new file mode 100755 index 0000000000..c7a815d263 --- /dev/null +++ b/scripts/generate-etcd-tls-certs.sh @@ -0,0 +1,71 @@ +#!/bin/bash + +# Generate TLS certificates for etcd testing +# This script creates certificates for TLS-enabled etcd in testing environments + +set -euo pipefail + +CERT_DIR="${1:-$(dirname "$0")/../tests-integration/fixtures/etcd-tls-certs}" +DAYS="${2:-365}" + +echo "Generating TLS certificates for etcd in ${CERT_DIR}..." + +mkdir -p "${CERT_DIR}" +cd "${CERT_DIR}" + +echo "Generating CA private key..." +openssl genrsa -out ca-key.pem 2048 + +echo "Generating CA certificate..." +openssl req -new -x509 -key ca-key.pem -out ca.crt -days "${DAYS}" \ + -subj "/C=US/ST=CA/L=SF/O=Greptime/CN=etcd-ca" + +# Create server certificate config with Subject Alternative Names +echo "Creating server certificate configuration..." +cat > server.conf << 'EOF' +[req] +distinguished_name = req +[v3_req] +basicConstraints = CA:FALSE +keyUsage = keyEncipherment, dataEncipherment +subjectAltName = @alt_names +[alt_names] +DNS.1 = localhost +DNS.2 = etcd-tls +DNS.3 = 127.0.0.1 +IP.1 = 127.0.0.1 +IP.2 = ::1 +EOF + +echo "Generating server private key..." +openssl genrsa -out server-key.pem 2048 + +echo "Generating server certificate signing request..." +openssl req -new -key server-key.pem -out server.csr \ + -subj "/CN=etcd-tls" + +echo "Generating server certificate..." +openssl x509 -req -in server.csr -CA ca.crt \ + -CAkey ca-key.pem -CAcreateserial -out server.crt \ + -days "${DAYS}" -extensions v3_req -extfile server.conf + +echo "Generating client private key..." +openssl genrsa -out client-key.pem 2048 + +echo "Generating client certificate signing request..." +openssl req -new -key client-key.pem -out client.csr \ + -subj "/CN=etcd-client" + +echo "Generating client certificate..." +openssl x509 -req -in client.csr -CA ca.crt \ + -CAkey ca-key.pem -CAcreateserial -out client.crt \ + -days "${DAYS}" + +echo "Setting proper file permissions..." +chmod 644 ca.crt server.crt client.crt +chmod 600 ca-key.pem server-key.pem client-key.pem + +# Clean up intermediate files +rm -f server.csr client.csr server.conf + +echo "TLS certificates generated successfully in ${CERT_DIR}" diff --git a/src/cli/src/metadata/common.rs b/src/cli/src/metadata/common.rs index 2455aa400c..960b13f065 100644 --- a/src/cli/src/metadata/common.rs +++ b/src/cli/src/metadata/common.rs @@ -19,8 +19,9 @@ use common_error::ext::BoxedError; use common_meta::kv_backend::chroot::ChrootKvBackend; use common_meta::kv_backend::etcd::EtcdStore; use common_meta::kv_backend::KvBackendRef; -use meta_srv::bootstrap::create_etcd_client; +use meta_srv::bootstrap::create_etcd_client_with_tls; use meta_srv::metasrv::BackendImpl; +use servers::tls::{TlsMode, TlsOption}; use crate::error::{EmptyStoreAddrsSnafu, UnsupportedMemoryBackendSnafu}; @@ -55,6 +56,26 @@ pub(crate) struct StoreConfig { #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))] #[clap(long, default_value = common_meta::kv_backend::DEFAULT_META_TABLE_NAME)] meta_table_name: String, + + /// TLS mode for backend store connections (etcd, PostgreSQL, MySQL) + #[clap(long = "backend-tls-mode", value_enum, default_value = "disable")] + backend_tls_mode: TlsMode, + + /// Path to TLS certificate file for backend store connections + #[clap(long = "backend-tls-cert-path", default_value = "")] + backend_tls_cert_path: String, + + /// Path to TLS private key file for backend store connections + #[clap(long = "backend-tls-key-path", default_value = "")] + backend_tls_key_path: String, + + /// Path to TLS CA certificate file for backend store connections + #[clap(long = "backend-tls-ca-cert-path", default_value = "")] + backend_tls_ca_cert_path: String, + + /// Enable watching TLS certificate files for changes + #[clap(long = "backend-tls-watch")] + backend_tls_watch: bool, } impl StoreConfig { @@ -67,7 +88,18 @@ impl StoreConfig { } else { let kvbackend = match self.backend { BackendImpl::EtcdStore => { - let etcd_client = create_etcd_client(store_addrs) + let tls_config = if self.backend_tls_mode != TlsMode::Disable { + Some(TlsOption { + mode: self.backend_tls_mode.clone(), + cert_path: self.backend_tls_cert_path.clone(), + key_path: self.backend_tls_key_path.clone(), + ca_cert_path: self.backend_tls_ca_cert_path.clone(), + watch: self.backend_tls_watch, + }) + } else { + None + }; + let etcd_client = create_etcd_client_with_tls(store_addrs, tls_config.as_ref()) .await .map_err(BoxedError::new)?; Ok(EtcdStore::with_etcd_client(etcd_client, max_txn_ops)) diff --git a/src/meta-srv/src/bootstrap.rs b/src/meta-srv/src/bootstrap.rs index d77ec335c1..86c917051d 100644 --- a/src/meta-srv/src/bootstrap.rs +++ b/src/meta-srv/src/bootstrap.rs @@ -21,6 +21,7 @@ use api::v1::meta::procedure_service_server::ProcedureServiceServer; use api::v1::meta::store_server::StoreServer; use common_base::Plugins; use common_config::Configurable; +#[cfg(feature = "pg_kvbackend")] use common_error::ext::BoxedError; #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))] use common_meta::distributed_time_constants::META_LEASE_SECS; @@ -40,7 +41,7 @@ use common_telemetry::info; #[cfg(feature = "pg_kvbackend")] use deadpool_postgres::{Config, Runtime}; use either::Either; -use etcd_client::Client; +use etcd_client::{Client, ConnectOptions}; use servers::configurator::ConfiguratorRef; use servers::export_metrics::ExportMetricsTask; use servers::http::{HttpServer, HttpServerBuilder}; @@ -286,7 +287,8 @@ pub async fn metasrv_builder( (Some(kv_backend), _) => (kv_backend, None), (None, BackendImpl::MemoryStore) => (Arc::new(MemoryKvBackend::new()) as _, None), (None, BackendImpl::EtcdStore) => { - let etcd_client = create_etcd_client(&opts.store_addrs).await?; + let etcd_client = + create_etcd_client_with_tls(&opts.store_addrs, opts.backend_tls.as_ref()).await?; let kv_backend = EtcdStore::with_etcd_client(etcd_client.clone(), opts.max_txn_ops); let election = EtcdElection::with_etcd_client( &opts.grpc.server_addr, @@ -435,12 +437,67 @@ pub async fn metasrv_builder( } pub async fn create_etcd_client(store_addrs: &[String]) -> Result { + create_etcd_client_with_tls(store_addrs, None).await +} + +fn build_connection_options(tls_config: Option<&TlsOption>) -> Result> { + use std::fs; + + use common_telemetry::debug; + use etcd_client::{Certificate, ConnectOptions, Identity, TlsOptions}; + use servers::tls::TlsMode; + + // If TLS options are not provided, return None + let Some(tls_config) = tls_config else { + return Ok(None); + }; + // If TLS is disabled, return None + if matches!(tls_config.mode, TlsMode::Disable) { + return Ok(None); + } + let mut etcd_tls_opts = TlsOptions::new(); + // Set CA certificate if provided + if !tls_config.ca_cert_path.is_empty() { + debug!("Using CA certificate from {}", tls_config.ca_cert_path); + let ca_cert_pem = fs::read(&tls_config.ca_cert_path).context(error::FileIoSnafu { + path: &tls_config.ca_cert_path, + })?; + let ca_cert = Certificate::from_pem(ca_cert_pem); + etcd_tls_opts = etcd_tls_opts.ca_certificate(ca_cert); + } + // Set client identity (cert + key) if both are provided + if !tls_config.cert_path.is_empty() && !tls_config.key_path.is_empty() { + debug!( + "Using client certificate from {} and key from {}", + tls_config.cert_path, tls_config.key_path + ); + let cert_pem = fs::read(&tls_config.cert_path).context(error::FileIoSnafu { + path: &tls_config.cert_path, + })?; + let key_pem = fs::read(&tls_config.key_path).context(error::FileIoSnafu { + path: &tls_config.key_path, + })?; + let identity = Identity::from_pem(cert_pem, key_pem); + etcd_tls_opts = etcd_tls_opts.identity(identity); + } + // Enable native TLS roots for additional trust anchors + etcd_tls_opts = etcd_tls_opts.with_native_roots(); + Ok(Some(ConnectOptions::new().with_tls(etcd_tls_opts))) +} + +pub async fn create_etcd_client_with_tls( + store_addrs: &[String], + tls_config: Option<&TlsOption>, +) -> Result { let etcd_endpoints = store_addrs .iter() .map(|x| x.trim()) .filter(|x| !x.is_empty()) .collect::>(); - Client::connect(&etcd_endpoints, None) + + let connect_options = build_connection_options(tls_config)?; + + Client::connect(&etcd_endpoints, connect_options) .await .context(error::ConnectEtcdSnafu) } @@ -533,3 +590,104 @@ pub async fn create_mysql_pool(store_addrs: &[String]) -> Result { Ok(pool) } + +#[cfg(test)] +mod tests { + use servers::tls::TlsMode; + + use super::*; + + #[tokio::test] + async fn test_create_etcd_client_tls_without_certs() { + let endpoints: Vec = match std::env::var("GT_ETCD_TLS_ENDPOINTS") { + Ok(endpoints_str) => endpoints_str + .split(',') + .map(|s| s.trim().to_string()) + .collect(), + Err(_) => return, + }; + + let tls_config = TlsOption { + mode: TlsMode::Require, + ca_cert_path: String::new(), + cert_path: String::new(), + key_path: String::new(), + watch: false, + }; + + let _client = create_etcd_client_with_tls(&endpoints, Some(&tls_config)) + .await + .unwrap(); + } + + #[tokio::test] + async fn test_create_etcd_client_tls_with_client_certs() { + let endpoints: Vec = match std::env::var("GT_ETCD_TLS_ENDPOINTS") { + Ok(endpoints_str) => endpoints_str + .split(',') + .map(|s| s.trim().to_string()) + .collect(), + Err(_) => return, + }; + + let cert_dir = std::env::current_dir() + .unwrap() + .join("tests-integration") + .join("fixtures") + .join("etcd-tls-certs"); + + if cert_dir.join("client.crt").exists() && cert_dir.join("client-key.pem").exists() { + let tls_config = TlsOption { + mode: TlsMode::Require, + ca_cert_path: String::new(), + cert_path: cert_dir.join("client.crt").to_string_lossy().to_string(), + key_path: cert_dir + .join("client-key.pem") + .to_string_lossy() + .to_string(), + watch: false, + }; + + let _client = create_etcd_client_with_tls(&endpoints, Some(&tls_config)) + .await + .unwrap(); + } + } + + #[tokio::test] + async fn test_create_etcd_client_tls_with_full_certs() { + let endpoints: Vec = match std::env::var("GT_ETCD_TLS_ENDPOINTS") { + Ok(endpoints_str) => endpoints_str + .split(',') + .map(|s| s.trim().to_string()) + .collect(), + Err(_) => return, + }; + + let cert_dir = std::env::current_dir() + .unwrap() + .join("tests-integration") + .join("fixtures") + .join("etcd-tls-certs"); + + if cert_dir.join("ca.crt").exists() + && cert_dir.join("client.crt").exists() + && cert_dir.join("client-key.pem").exists() + { + let tls_config = TlsOption { + mode: TlsMode::Require, + ca_cert_path: cert_dir.join("ca.crt").to_string_lossy().to_string(), + cert_path: cert_dir.join("client.crt").to_string_lossy().to_string(), + key_path: cert_dir + .join("client-key.pem") + .to_string_lossy() + .to_string(), + watch: false, + }; + + let _client = create_etcd_client_with_tls(&endpoints, Some(&tls_config)) + .await + .unwrap(); + } + } +} diff --git a/src/meta-srv/src/error.rs b/src/meta-srv/src/error.rs index e389e548ea..b5ef3879ce 100644 --- a/src/meta-srv/src/error.rs +++ b/src/meta-srv/src/error.rs @@ -257,6 +257,15 @@ pub enum Error { location: Location, }, + #[snafu(display("Failed to read file: {}", path))] + FileIo { + #[snafu(source)] + error: std::io::Error, + #[snafu(implicit)] + location: Location, + path: String, + }, + #[snafu(display("Failed to bind address {}", addr))] TcpBind { addr: String, @@ -970,6 +979,7 @@ impl ErrorExt for Error { match self { Error::EtcdFailed { .. } | Error::ConnectEtcd { .. } + | Error::FileIo { .. } | Error::TcpBind { .. } | Error::SerializeToJson { .. } | Error::DeserializeFromJson { .. } diff --git a/tests-integration/README.md b/tests-integration/README.md index ea68e16969..550f4648e1 100644 --- a/tests-integration/README.md +++ b/tests-integration/README.md @@ -54,3 +54,45 @@ cd tests-integration/fixtures docker compose -f docker-compose.yml up kafka ``` + +## Setup tests with etcd TLS + +This guide explains how to set up and test TLS-enabled etcd connections in GreptimeDB integration tests. + +### Quick Start + +TLS certificates are already at `tests-integration/fixtures/etcd-tls-certs/`. + +1. **Start TLS-enabled etcd**: + ```bash + cd tests-integration/fixtures + docker compose up etcd-tls -d + ``` + +2. **Start all services (including etcd-tls)**: + ```bash + cd tests-integration/fixtures + docker compose up -d --wait + ``` + +### Certificate Details + +The checked-in certificates include: +- `ca.crt` - Certificate Authority certificate +- `server.crt` / `server-key.pem` - Server certificate for etcd-tls service +- `client.crt` / `client-key.pem` - Client certificate for connecting to etcd-tls + +The server certificate includes SANs for `localhost`, `etcd-tls`, `127.0.0.1`, and `::1`. + +### Regenerating Certificates (Optional) + +If you need to regenerate the certificates: +```bash +# Regenerate certificates (overwrites existing ones) +./scripts/generate-etcd-tls-certs.sh + +# Or generate in custom location +./scripts/generate-etcd-tls-certs.sh /path/to/cert/directory +``` + +**Note**: The checked-in certificates are for testing purposes only and should never be used in production. \ No newline at end of file diff --git a/tests-integration/fixtures/docker-compose.yml b/tests-integration/fixtures/docker-compose.yml index ef0206d4f0..8e435e47d4 100644 --- a/tests-integration/fixtures/docker-compose.yml +++ b/tests-integration/fixtures/docker-compose.yml @@ -43,6 +43,33 @@ services: ETCD_ADVERTISE_CLIENT_URLS: http://etcd:2379 ETCD_MAX_REQUEST_BYTES: 10485760 + etcd-tls: + image: docker.io/bitnami/etcd:3.5 + ports: + - "2378:2378" + - "2381:2381" + environment: + ALLOW_NONE_AUTHENTICATION: "yes" + ETCD_NAME: etcd-tls + ETCD_LISTEN_CLIENT_URLS: https://0.0.0.0:2378 + ETCD_ADVERTISE_CLIENT_URLS: https://etcd-tls:2378 + ETCD_LISTEN_PEER_URLS: https://0.0.0.0:2381 + ETCD_INITIAL_ADVERTISE_PEER_URLS: https://etcd-tls:2381 + ETCD_INITIAL_CLUSTER: etcd-tls=https://etcd-tls:2381 + ETCD_INITIAL_CLUSTER_TOKEN: etcd-tls-cluster + ETCD_INITIAL_CLUSTER_STATE: new + ETCD_CERT_FILE: /certs/server.crt + ETCD_KEY_FILE: /certs/server-key.pem + ETCD_TRUSTED_CA_FILE: /certs/ca.crt + ETCD_PEER_CERT_FILE: /certs/server.crt + ETCD_PEER_KEY_FILE: /certs/server-key.pem + ETCD_PEER_TRUSTED_CA_FILE: /certs/ca.crt + ETCD_CLIENT_CERT_AUTH: "true" + ETCD_PEER_CLIENT_CERT_AUTH: "true" + ETCD_MAX_REQUEST_BYTES: 10485760 + volumes: + - ./etcd-tls-certs:/certs:ro + minio: image: docker.io/bitnami/minio:2024 ports: diff --git a/tests-integration/fixtures/etcd-tls-certs/ca-key.pem b/tests-integration/fixtures/etcd-tls-certs/ca-key.pem new file mode 100644 index 0000000000..2066dfb7b4 --- /dev/null +++ b/tests-integration/fixtures/etcd-tls-certs/ca-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCfIi0iTllUQyNY +ka+d9Zt30ILA0QBzLKHwez9QJj8bQLpfKR26d794CQn/OO6XO7MWsJ6nvqwRNYM0 +WX+UwUtuT9MrttYWpS5yEAVO79dMtF67gCNafXKjQyK8L1vz6Avq4XJN4VqZEifT +Fdk3s2MmS0twv4sgrK//jh7aZzBQJtw+ROe9RN1dqlKoa3TtpB7iwNTDxGiR0EYj +wHj+GdiNHtDMWvrnTNNX/IKeEwLP/Mjirzr7GnaOjR25ruqcLuwWrufu+EMhqFTU +r+LIQpZD0TFuPX6DPlQZOs/4UpjteoC84m5AnQXNlh0vzjbW1efEYWYQoKDesx9e +oE5jcABpAgMBAAECggEAA3Rw/r6CYaTG1tdBilA47LF/XTihu15mh6Y4BNadESDn +IEYav0p2mDW4sgH7lWyg4ecPaBHo124jfUFM1p8Zsvk9sERwbR5vSIpWKyq5hbtM +Fo2yIXakGgJM9ev19vDR7WqxRMVAkR6GnyZpcwmh0e+ENvGZpNR1n7qSAJOJRibW +Ye8qMF/zMLF9VekBRPFJFIZBvKgHxSGCLbXRzsi5LKMbwfBoJmxEZSOC9zODl43o +Z2i+LvlS0R/Rsf2KG+Hwgj1P7HH1znJeA5bVJFDewljjSwu1mk0JpQL7Jgp2xpqs +F/mRZmtoQSH3EsTm2Kjz1sLGXwUb9JaQ274aV4t7pwKBgQDXYF+qFYip7k+b9FTF +sFbfp3CjOqxXiAxnoE5hlfV/h0w4V1Su42AdejnbIVYFX8bvmezkNWPXhB6P5oHU +4nO+oAuhsRT4317mfRM5NWO6mv2eglSBnS04GLsX142A7jMPr9e+Cqh4dYfw/A1L +bSdsdILemTFQrak27pC11mHZOwKBgQC9JhDhQf5uRh6k8GvgKGu9ZEZmkYCVu2sr +7kpD60UhklnyQo6DKYsa6OcChRQMv9ss3Hqu3Y1G0/sTe1Tjz5zwrWWAZoLlbdOt +vipesvwNTxvJoUWPtrjOoFZtmyg0Q0TqxaxfEWAssDU9IfnIy+zx7sAg4zZIPUyy +6kudaY1SqwKBgQCAQ/71Fjn7qddzc4GA8lHqhJeKPokg3/8zP78uUtaQCo2UCD6A +oR0+sOn/3MyUCsQ5MZxpFHrPgPmKjabIl8yCvGHw+7sXtD+aWOa37VnlaiSc39Vg +E7E4dVIHEvJM1I9ISlrb7REEHErHc/Se9PTDnGfMFcPO3n2mH1HDWVeQvQKBgGGn +BHH3a08tXmbTRS5uT+lwmrQbjKJBJ3x/wtG75m4Fq/BaEk9/JDUZZyKy5/4JEzPf +BGvBME4P5QFS3CndJu5O5ydaRVwDzpRVqHRJvb11SShY3Zvrvw/WUai2wRPyYuM+ +eNaAFwIbWvEb2GSle8gP9htEkuLK2w1HzxAOzYqPAoGAKl5l/WsoLfQP5UIUjSQe +JtVTDVmoz8m8Mg2nn56UdUetG246EVhDx5ngj84kZDM0GDXhfVWV6MWnIZr5NQsr +bORIDNP7Czat8FnlXeAQ+R6A/87o5g5p6ydH9jYqrrLxYjaZyXJptE+ja4zW7Lbl +ogWAc76iZvXLXqKRfepG0zQ= +-----END PRIVATE KEY----- diff --git a/tests-integration/fixtures/etcd-tls-certs/ca.crt b/tests-integration/fixtures/etcd-tls-certs/ca.crt new file mode 100644 index 0000000000..8723f7ffed --- /dev/null +++ b/tests-integration/fixtures/etcd-tls-certs/ca.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDeTCCAmGgAwIBAgIUeRD4bMVd0XEzS3UHo2ptnknsWzEwDQYJKoZIhvcNAQEL +BQAwTDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQHDAJTRjERMA8G +A1UECgwIR3JlcHRpbWUxEDAOBgNVBAMMB2V0Y2QtY2EwHhcNMjUwODI1MTgwNjU1 +WhcNMjYwODI1MTgwNjU1WjBMMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExCzAJ +BgNVBAcMAlNGMREwDwYDVQQKDAhHcmVwdGltZTEQMA4GA1UEAwwHZXRjZC1jYTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ8iLSJOWVRDI1iRr531m3fQ +gsDRAHMsofB7P1AmPxtAul8pHbp3v3gJCf847pc7sxawnqe+rBE1gzRZf5TBS25P +0yu21halLnIQBU7v10y0XruAI1p9cqNDIrwvW/PoC+rhck3hWpkSJ9MV2TezYyZL +S3C/iyCsr/+OHtpnMFAm3D5E571E3V2qUqhrdO2kHuLA1MPEaJHQRiPAeP4Z2I0e +0Mxa+udM01f8gp4TAs/8yOKvOvsado6NHbmu6pwu7Bau5+74QyGoVNSv4shClkPR +MW49foM+VBk6z/hSmO16gLzibkCdBc2WHS/ONtbV58RhZhCgoN6zH16gTmNwAGkC +AwEAAaNTMFEwHQYDVR0OBBYEFOCkI3Uyx7F38LtXtSlg3ORE9ur6MB8GA1UdIwQY +MBaAFOCkI3Uyx7F38LtXtSlg3ORE9ur6MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI +hvcNAQELBQADggEBAJXbWJJ9b+5nXjRiFXOg+wQnzn7kzMf6sWKIFk+AuKJWWt78 +O00t6vyAz6zel5Cj3ho9yAaMFNy8vYEnJCYngy5pT/2hOncnz/w7IKTeoEhzqAnf +MCEmCgHbTKDoFfMfrrRwtyoePVfx4xbiGVWMQFTPG+WNlE/ivFMRvFwsgPJ+7SUK +mR2FscH6DVo4sqF6s729lTmr6/U7bOD5l2HYGpKJ2cjCI8+HDv55aAT43tsTwBoJ +BgX+RT4w8ryGhYV+hrRTjPlMHWiHsNbzJeAi5bNA0f6vUP6k6zHn/Ur3MNb1avcf +cSsdYU2dhs7PeB6IpoJ0QCeJw9MIFK3XTnmbeVY= +-----END CERTIFICATE----- diff --git a/tests-integration/fixtures/etcd-tls-certs/ca.srl b/tests-integration/fixtures/etcd-tls-certs/ca.srl new file mode 100644 index 0000000000..69ac026da2 --- /dev/null +++ b/tests-integration/fixtures/etcd-tls-certs/ca.srl @@ -0,0 +1 @@ +4484A9BBD4F25F32994F3C03D80D294105B119E6 diff --git a/tests-integration/fixtures/etcd-tls-certs/client-key.pem b/tests-integration/fixtures/etcd-tls-certs/client-key.pem new file mode 100644 index 0000000000..13a23c5347 --- /dev/null +++ b/tests-integration/fixtures/etcd-tls-certs/client-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCOcrzRmE3sEGYo +pazDrpkkzbiaBhHClfmBiZAAGV2cvSXY8e9pc21GOgrGBNeyPPieS305rAE02EZl +oIAt97XRFxkZniUy8C5+PT3eicAKPRcrgGhIrYxUs39rdRocqVVpZsiZGzhHhboB +bXNW1l37SDQpuxAQJuhHu2wu9J7c5/TBXWN9ZOxzWTlrIdEQOA46VclE/N1TlaKs +CSWw8qH87YLwkLEXcFLOJfmWNZxOOhdL5MSzKKNcQKbpmkd65B/PHNwBIBZHpI+K +xphK1SybA+ESkN09qZaa1Kj3e0I62UjHNXUCuAod6RhRRmpiFDFgggXhD9T9Ttuf +1Lq38XxDAgMBAAECggEAANNhqQldwHzi9WCxXObLoufBe9lM73+1Df1IQaDHkZR3 +jHliixxF18XQW7qZ5tAJqjsDWLPm4BxSKXozsjsvBdgIUjbqkyx1dsGlO9TjeGu5 +H2/8jlH14boIMWJ9Y0JBWwvU7EnVU5IkUOEiwsxvFlzM5Q0H+841CrSD+Xd7iSZE +ZrpyZgpHNmvc/u7AmseZVccjX21dxwWtcd7cGUmFWC9o2a/hkgG6+baA8zH2ze3J +Smeowa/oOyOVkTM1EHLCBvddE+/W+BeMGPY7A6SztVw0gLqlSOL3cr/g2llUTmFg +T6MOS6FZZ7MD5c2HBL0V3OXIhxNABzD+c0O3CaRbSQKBgQC/+QuhMpDCzxBPaL/K +sqRp4sQgURDCXPA1nAfI+NoHos/CbjwcMGp6LUSiBW0tLTJ+LZoVgZXj6j/uxji9 +DWxQfULvQ7oanm/q/D+40NnupQQTzmMT04z/mV3XjFtzEhbO30YZfqwXy+tqB8vR +g1KajXVqLmCxKDtsFedAlIVxRQKBgQC99TKGcBwsKlYJJThU2eIIy8G0GkjjXleK +ROMO5i0keJtLac1oRvXo4JN5UBLJM6ZpSy0TEa2bxfzy6Uea+41aZmdCpPg0Kcsq +Pb1S3rsPpVdsfxSxsdKvwZmHXOzAdF+fom1+ZRAdo/8ALIPaNQSSaw+KkmmpHPEV +qdzzWJ4b5wKBgFubEtKcF3nuZwENoh+ueUhRvncRV+b3hGSAjTJ4lUn5hhxoj+R/ +sf+VJGAQKNXa8HJHfnRuvsDgYhulmSOViS8rZspXzjGvkwZV0m51stjvA3AUFzE5 +zNmXLLGTt3vEkP+siX3W9XXxh+ezyq2ydbNsdy/w65D9+sUL+qrVdIvlAoGAOOQy +2ajCB0g2tE59bIxE8jV0MiidI9uhhDvVdSTi6EVm3VM2vcBi7fg0suSUe8YIVQi6 +2zc0M688btQHKhek4ipBSuh1ncnWmzQae7NRewIeCNSWshF79D+bZ7sg/RLdgMX4 +3R4PkZEIUlkCtFuknuWJpgrrskaEveQ91HP6BokCgYAX42nKPANIMrTXuJ2vACWu +qKQ9atAC1ngVzYe2PI8rHjA4gCDraGfCaILewrd89rK9ukBeSDIm5Mn448q3ystw +p/QMxmMdHADCD6UwCjlt9N0Xigv+IKbDzDzhartRVIPpZdTViQXW3cSHt9id8zvO +HTu5C6W+N9Vb7j8Ak/mvzw== +-----END PRIVATE KEY----- diff --git a/tests-integration/fixtures/etcd-tls-certs/client.crt b/tests-integration/fixtures/etcd-tls-certs/client.crt new file mode 100644 index 0000000000..935351a48b --- /dev/null +++ b/tests-integration/fixtures/etcd-tls-certs/client.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDMjCCAhqgAwIBAgIURISpu9TyXzKZTzwD2A0pQQWxGeYwDQYJKoZIhvcNAQEL +BQAwTDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQHDAJTRjERMA8G +A1UECgwIR3JlcHRpbWUxEDAOBgNVBAMMB2V0Y2QtY2EwHhcNMjUwODI1MTgwNjU1 +WhcNMjYwODI1MTgwNjU1WjAWMRQwEgYDVQQDDAtldGNkLWNsaWVudDCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAI5yvNGYTewQZiilrMOumSTNuJoGEcKV ++YGJkAAZXZy9Jdjx72lzbUY6CsYE17I8+J5LfTmsATTYRmWggC33tdEXGRmeJTLw +Ln49Pd6JwAo9FyuAaEitjFSzf2t1GhypVWlmyJkbOEeFugFtc1bWXftINCm7EBAm +6Ee7bC70ntzn9MFdY31k7HNZOWsh0RA4DjpVyUT83VOVoqwJJbDyofztgvCQsRdw +Us4l+ZY1nE46F0vkxLMoo1xApumaR3rkH88c3AEgFkekj4rGmErVLJsD4RKQ3T2p +lprUqPd7QjrZSMc1dQK4Ch3pGFFGamIUMWCCBeEP1P1O25/UurfxfEMCAwEAAaNC +MEAwHQYDVR0OBBYEFINcPBk3iqCw1B2sZzcDpSF6ZNGnMB8GA1UdIwQYMBaAFOCk +I3Uyx7F38LtXtSlg3ORE9ur6MA0GCSqGSIb3DQEBCwUAA4IBAQBgyF1XSpAyiQNA +sFCqXrBfwPnv6V+R5jhO6Glmn+Nhj0gbzNBlU8EKsK/WZllDrJjmxubPBqb563Zt +J+QcNLqugZdioXPbxmmi9xj3oK25pUCRBj03nlHpGqIwuCJyn/ZxlfXMpNYE1KjM +nprFNUKgnYPk2AGffAngQdm0yrnmSpxXhNTuhQE8avgRhd5nEUEDyPIvHWwo4iU6 +pw2aP2FpWorESv9LVna+JortThYDQrIFgCtPM6BP1N7Aeqn0H846+JsXlq2ch1Iy +aBRqKNQRc1Q2Qb9/QCDEJ3dEixgFjxztIaqrIcr18ZJ797MhTFS3aVEwE8clSRR5 +9ow9jK8B +-----END CERTIFICATE----- diff --git a/tests-integration/fixtures/etcd-tls-certs/server-key.pem b/tests-integration/fixtures/etcd-tls-certs/server-key.pem new file mode 100644 index 0000000000..fca8a0122f --- /dev/null +++ b/tests-integration/fixtures/etcd-tls-certs/server-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCtYFxH+oet6jTD +0eF55ISO+bwm1NPTluP9zLJrQFNDkqlddyiIasK5q7qN1pPXOw9mJF/EN8Hf1lWj +42an6tr7PgE0NHLcOrqDv4dRjegRi87IWiPkfep8peUE3glI4IOMXfZmAUNp+nRO +JP/ymmR0pzHYJlx+D082OYmeBny7uFQxo+vxgVNo2MVVwy6oTv+jtjLgZ4iOrIvh +iILoXtXcdg/tjB1rS2hSABGPJMNHwKswcrt6xXv+7Llsxroq0cx0E2PrAbc5qB40 +v1Qp7PjFTJ0drgf0g51LkOb7znpB1viPD2BLMxpELTZqa4OruarcDNxShrK8WWMP +1mygLHLxAgMBAAECggEAC4TgtLaQP62VImKGLs1QQliU1+ahiUgX70Ojog0UyyNK +JefWFVQ0ilX+z9AvI+hsYj6t7zE+LBNHPtuLtUHdGT66IUAP1pJ/VGQMB07cmZfW +ngihJFv6UZxLDkr7RnCGRPP0PDw+wKKPiiaaq8F2xapbHS+VSxnUyzdA7bMkI+uj ++gLAFj+kEU0FNbIp/mBzz8sksDzcB29oy3VnZkR1211KkL1BJDvr9oKiUg8NFKaN +NF2WXRYI/m0CQMlX6zlTyv7+h/Ay7y8oNG7cfHavmCrWvYIMfaDggYxbIpNdGxb5 +MAdbrtXJ6daUBa2sezxgQUyJX8+8GGF2zpGvCfhkfQKBgQDiAwA8rlxrBnXclwRK +9s/apILKCxPEGwU6XZi/8na3ugIO14y2WD0zZTjUK/3xwoKN6j6+ObLkUBX2RRYZ +ewwxpqos2cyxi5EBKPhsydqbJQlat68I5+NOG4KOZQkqO92tBtgY3gGFWVntaqtE +UVE/Clh2gFcc/5nR/5C5Mil8LQKBgQDEYXtrl2kl4qcyXuuXKDA/bLSnDuIEMhLO +4oIiqmywXQgjPjGAWy0eztjMq2a353pqTFCqto/cfOif+rjkB7oFfi9gMm0plIKI ++F8QsBB7HpGqWos3zb1yt8X9hbxKuFFwZS/un3Li4lwPlk8EZ1YIvhC44BHAvNkD +VzxzBwoYVQKBgArRe/RroC7bS074x5LTB5X+o+gJ6bNMW860Zjhh4b7fn3OYa7ra +tGs+YB7/0BL/bYJfgQtX9bEqCDMWkX08v5Os1553+m1RMeqtTF7gtp8Qgcce3bj+ +aIn3lSM9wNeNsAm1NyjRj58TbNOJdJM7lTkARMW/VOwla/Z6VjIXLZctAoGBAJKf +xira7eMfi36MaJJ/qyZv36Ir9ozzZh+Z91gyrtwvWfgWY5dWfCXYgv6tqw/8gOYE +/OW5UUhq6rUn2gxHyJh5Up4ciGzXOW9TIoevLV7/v/rVh8SulJimpelYhPG1FPk6 +U8NywbCtGdd5fp3nGdGFN68Rfa/OUKmx5KxtwRfRAoGAWpfzmoI8EmCBZNXYk03k +hnDKmICsKi9seDclcQq2PbyNvE7LDEd8O4pDnwV6RwKVEDTer9Y4IGcjkEBZcJVm +za3l4En9+M27Xlf1I8XeB8o8RYbFjoDQyScFFIgQpvTDsOezXeDR55FGPZN7V6Si +lKmd+8BuzJ7d31KJtRjoS1U= +-----END PRIVATE KEY----- diff --git a/tests-integration/fixtures/etcd-tls-certs/server.crt b/tests-integration/fixtures/etcd-tls-certs/server.crt new file mode 100644 index 0000000000..6ed8b1054e --- /dev/null +++ b/tests-integration/fixtures/etcd-tls-certs/server.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDjDCCAnSgAwIBAgIURISpu9TyXzKZTzwD2A0pQQWxGeUwDQYJKoZIhvcNAQEL +BQAwTDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQHDAJTRjERMA8G +A1UECgwIR3JlcHRpbWUxEDAOBgNVBAMMB2V0Y2QtY2EwHhcNMjUwODI1MTgwNjU1 +WhcNMjYwODI1MTgwNjU1WjATMREwDwYDVQQDDAhldGNkLXRsczCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAK1gXEf6h63qNMPR4XnkhI75vCbU09OW4/3M +smtAU0OSqV13KIhqwrmruo3Wk9c7D2YkX8Q3wd/WVaPjZqfq2vs+ATQ0ctw6uoO/ +h1GN6BGLzshaI+R96nyl5QTeCUjgg4xd9mYBQ2n6dE4k//KaZHSnMdgmXH4PTzY5 +iZ4GfLu4VDGj6/GBU2jYxVXDLqhO/6O2MuBniI6si+GIguhe1dx2D+2MHWtLaFIA +EY8kw0fAqzByu3rFe/7suWzGuirRzHQTY+sBtzmoHjS/VCns+MVMnR2uB/SDnUuQ +5vvOekHW+I8PYEszGkQtNmprg6u5qtwM3FKGsrxZYw/WbKAscvECAwEAAaOBnjCB +mzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEMDBBBgNVHREEOjA4gglsb2NhbGhvc3SC +CGV0Y2QtdGxzggkxMjcuMC4wLjGHBH8AAAGHEAAAAAAAAAAAAAAAAAAAAAEwHQYD +VR0OBBYEFK8y9gWv8Si9AusP280BrgDF6y3jMB8GA1UdIwQYMBaAFOCkI3Uyx7F3 +8LtXtSlg3ORE9ur6MA0GCSqGSIb3DQEBCwUAA4IBAQBMBsAPIlk17I2ioN9xwxwl +yYbSjZlTs+18wSZAoCNLfxwWIYAQ08dPoEUdALfMUPEEe1Ol2IAp/qx2JoDrZWje +maA43hppBUpFFCkTKWUMYxsetN7d7BVxWL43GDoMwoD/k36nhoUKBUjlbF0+nkem +dOMr8SA4GZbEg7qk2cL93g0UHv/Z/dZgKf3epZkR9hEN4/R2jSP6OPmY9XIvQCoZ +8D9jgbQKavAAXmUcP5a81alQMRroGaBCzI1f5OlS3EuVE7ZTEBgxKK1idbouSrPt +4UHEbOGz9zXDjmfut6CTm247+lJm9jzYe2Xx+XGw29l0pzd/8tGFN9zIvW8mCv7a +-----END CERTIFICATE-----