diff --git a/.github/services/aliyun_drive/aliyun_drive/disable_action.yml b/.github/services/aliyun_drive/aliyun_drive/disable_action.yml index c2642e088393..f4f8ce46c76b 100644 --- a/.github/services/aliyun_drive/aliyun_drive/disable_action.yml +++ b/.github/services/aliyun_drive/aliyun_drive/disable_action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/azblob/azure_azblob/action.yml b/.github/services/azblob/azure_azblob/action.yml index 64a2f5820408..04920eeab377 100644 --- a/.github/services/azblob/azure_azblob/action.yml +++ b/.github/services/azblob/azure_azblob/action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/azdls/azdls/action.yml b/.github/services/azdls/azdls/action.yml index 31fc7bb386fd..2cde8bbf5582 100644 --- a/.github/services/azdls/azdls/action.yml +++ b/.github/services/azdls/azdls/action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/azfile/azfile/action.yml b/.github/services/azfile/azfile/action.yml index afefd1a157ee..963fb47a0b3c 100644 --- a/.github/services/azfile/azfile/action.yml +++ b/.github/services/azfile/azfile/action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/b2/b2/action.yml b/.github/services/b2/b2/action.yml index a8fb2ccef263..b1e78356f670 100644 --- a/.github/services/b2/b2/action.yml +++ b/.github/services/b2/b2/action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/cos/cos/action.yml b/.github/services/cos/cos/action.yml index e98ab07f5857..675277251a2e 100644 --- a/.github/services/cos/cos/action.yml +++ b/.github/services/cos/cos/action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/dropbox/dropbox/disable_action.yml b/.github/services/dropbox/dropbox/disable_action.yml index fea5c1d1604f..30d3660a34fe 100644 --- a/.github/services/dropbox/dropbox/disable_action.yml +++ b/.github/services/dropbox/dropbox/disable_action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup credentials - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/etcd/etcd-server-tls/action.yml b/.github/services/etcd/etcd-server-tls/action.yml new file mode 100644 index 000000000000..38d33289f514 --- /dev/null +++ b/.github/services/etcd/etcd-server-tls/action.yml @@ -0,0 +1,42 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +name: etcd-server-tls +description: 'Behavior test for etcd with server-authenticated TLS' + +runs: + using: "composite" + steps: + - name: Copy Etcd Certificate Files + shell: bash + working-directory: fixtures + run: | + mkdir -p /tmp/etcd + cp -r "$(pwd)/etcd/"* /tmp/etcd + - name: Setup etcd server TLS + shell: bash + working-directory: fixtures/etcd + run: docker compose -f docker-compose-standalone-server-tls.yml up -d --wait + - name: Setup + shell: bash + run: | + cat << EOF >> "$GITHUB_ENV" + OPENDAL_ETCD_ENDPOINTS=https://127.0.0.1:2379 + OPENDAL_ETCD_ROOT=/tmp/opendal + OPENDAL_ETCD_CA_PATH=/tmp/etcd/ca.pem + OPENDAL_ETCD_MAX_DECODING_MESSAGE_SIZE=10485760 + EOF diff --git a/.github/services/gcs/gcs/action.yml b/.github/services/gcs/gcs/action.yml index 2dbe11c4b487..334f5dbc260a 100644 --- a/.github/services/gcs/gcs/action.yml +++ b/.github/services/gcs/gcs/action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/gcs/gcs_with_default_storage_class/action.yml b/.github/services/gcs/gcs_with_default_storage_class/action.yml index d5f9de8d9bdd..b496cf031afb 100644 --- a/.github/services/gcs/gcs_with_default_storage_class/action.yml +++ b/.github/services/gcs/gcs_with_default_storage_class/action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/gcs_grpc/gcs_grpc/action.yml b/.github/services/gcs_grpc/gcs_grpc/action.yml index ab0e4c4d72c4..ffc80c918725 100644 --- a/.github/services/gcs_grpc/gcs_grpc/action.yml +++ b/.github/services/gcs_grpc/gcs_grpc/action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/gdrive/gdrive/action.yml b/.github/services/gdrive/gdrive/action.yml index 0d0e4d7c1019..b9a9e7995917 100644 --- a/.github/services/gdrive/gdrive/action.yml +++ b/.github/services/gdrive/gdrive/action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/hdfs/hdfs_default_gcs/action.yml b/.github/services/hdfs/hdfs_default_gcs/action.yml index 01da1d369106..c56f9b753241 100644 --- a/.github/services/hdfs/hdfs_default_gcs/action.yml +++ b/.github/services/hdfs/hdfs_default_gcs/action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Load secrets - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/hf/hf_bucket/action.yml b/.github/services/hf/hf_bucket/action.yml index 9ecdb5b7e4fb..170866f39d0a 100644 --- a/.github/services/hf/hf_bucket/action.yml +++ b/.github/services/hf/hf_bucket/action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/hf/hf_bucket_http/action.yml b/.github/services/hf/hf_bucket_http/action.yml index 2d2a9bd1549e..3c0cb29e2e93 100644 --- a/.github/services/hf/hf_bucket_http/action.yml +++ b/.github/services/hf/hf_bucket_http/action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/hf/hf_dataset/action.yml b/.github/services/hf/hf_dataset/action.yml index b5390e55a7d4..bc40e13f06d1 100644 --- a/.github/services/hf/hf_dataset/action.yml +++ b/.github/services/hf/hf_dataset/action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/koofr/koofr/disable_action.yml b/.github/services/koofr/koofr/disable_action.yml index 7fdda9fe4746..747a3794bde7 100644 --- a/.github/services/koofr/koofr/disable_action.yml +++ b/.github/services/koofr/koofr/disable_action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/oss/oss/action.yml b/.github/services/oss/oss/action.yml index 219269e0f454..b2ae4c7beb47 100644 --- a/.github/services/oss/oss/action.yml +++ b/.github/services/oss/oss/action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/oss/oss_with_versioning/action.yml b/.github/services/oss/oss_with_versioning/action.yml index 419026a4235b..d709f4300b4b 100644 --- a/.github/services/oss/oss_with_versioning/action.yml +++ b/.github/services/oss/oss_with_versioning/action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/s3/aws_s3/action.yml b/.github/services/s3/aws_s3/action.yml index 2ec99e1bca0a..5bba9166d1a8 100644 --- a/.github/services/s3/aws_s3/action.yml +++ b/.github/services/s3/aws_s3/action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/s3/aws_s3_express/action.yml b/.github/services/s3/aws_s3_express/action.yml index 2a8cc554fe41..2cf17dddebb3 100644 --- a/.github/services/s3/aws_s3_express/action.yml +++ b/.github/services/s3/aws_s3_express/action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/s3/aws_s3_with_list_objects_v1/action.yml b/.github/services/s3/aws_s3_with_list_objects_v1/action.yml index ade3509bdf9b..1f838cfb7262 100644 --- a/.github/services/s3/aws_s3_with_list_objects_v1/action.yml +++ b/.github/services/s3/aws_s3_with_list_objects_v1/action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/s3/aws_s3_with_sse_c/action.yml b/.github/services/s3/aws_s3_with_sse_c/action.yml index dcdf3eeb65eb..6c4f58696da1 100644 --- a/.github/services/s3/aws_s3_with_sse_c/action.yml +++ b/.github/services/s3/aws_s3_with_sse_c/action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/s3/aws_s3_with_versioning/action.yml b/.github/services/s3/aws_s3_with_versioning/action.yml index 43e6cb1aaa73..41275bc92ff1 100644 --- a/.github/services/s3/aws_s3_with_versioning/action.yml +++ b/.github/services/s3/aws_s3_with_versioning/action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/s3/aws_s3_with_virtual_host/action.yml b/.github/services/s3/aws_s3_with_virtual_host/action.yml index aaab81a924ad..42181ef734a5 100644 --- a/.github/services/s3/aws_s3_with_virtual_host/action.yml +++ b/.github/services/s3/aws_s3_with_virtual_host/action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/s3/neon/disabled_action.yml b/.github/services/s3/neon/disabled_action.yml index b5ccd3686768..285701ed5ed1 100644 --- a/.github/services/s3/neon/disabled_action.yml +++ b/.github/services/s3/neon/disabled_action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/s3/r2/disabled_action.yml b/.github/services/s3/r2/disabled_action.yml index 5fcb67faffd3..0d842c231a4e 100644 --- a/.github/services/s3/r2/disabled_action.yml +++ b/.github/services/s3/r2/disabled_action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/services/tos/tos/action.yml b/.github/services/tos/tos/action.yml index 164ac8271157..2d5f03396c4a 100644 --- a/.github/services/tos/tos/action.yml +++ b/.github/services/tos/tos/action.yml @@ -22,7 +22,7 @@ runs: using: "composite" steps: - name: Setup - uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 + uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 with: export-env: true env: diff --git a/.github/workflows/ci_bindings_haskell.yml b/.github/workflows/ci_bindings_haskell.yml index 5413880317de..818ef726fa94 100644 --- a/.github/workflows/ci_bindings_haskell.yml +++ b/.github/workflows/ci_bindings_haskell.yml @@ -174,7 +174,7 @@ jobs: # name: bindings-haskell-sdist # - name: Load secret # id: op-load-secret -# uses: 1Password/load-secrets-action@eb2efd0703da22a93c467f2d1ffbb6826c11e19c # v4.1.1 +# uses: 1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5.0.1 # with: # export-env: true # env: diff --git a/bindings/dotnet/OpenDAL/ServiceConfig/EtcdServiceConfig.cs b/bindings/dotnet/OpenDAL/ServiceConfig/EtcdServiceConfig.cs index 134695fcb33c..1d26f8440f83 100644 --- a/bindings/dotnet/OpenDAL/ServiceConfig/EtcdServiceConfig.cs +++ b/bindings/dotnet/OpenDAL/ServiceConfig/EtcdServiceConfig.cs @@ -29,19 +29,19 @@ namespace OpenDAL.ServiceConfig public sealed class EtcdServiceConfig : IServiceConfig { /// - /// certificate authority file path default is None + /// PEM certificate authority file used to verify the server. Enables TLS independently of `cert_path` and `key_path`. default is None /// public string? CaPath { get; init; } /// - /// cert path default is None + /// PEM client certificate file used for mutual TLS. Must be configured together with `key_path`. default is None /// public string? CertPath { get; init; } /// - /// network address of the Etcd services. If use https, must set TLS options: `ca_path`, `cert_path`, `key_path`. e.g. "127.0.0.1:23790,127.0.0.1:23791,127.0.0.1:23792" or "http://127.0.0.1:23790,http://127.0.0.1:23791,http://127.0.0.1:23792" or "https://127.0.0.1:23790,https://127.0.0.1:23791,https://127.0.0.1:23792" default is "http://127.0.0.1:2379" + /// network address of the Etcd services. Use HTTPS endpoints for TLS. Set `ca_path` to trust a custom certificate authority. Client authentication additionally requires both `cert_path` and `key_path`. e.g. "127.0.0.1:23790,127.0.0.1:23791,127.0.0.1:23792" or "http://127.0.0.1:23790,http://127.0.0.1:23791,http://127.0.0.1:23792" or "https://127.0.0.1:23790,https://127.0.0.1:23791,https://127.0.0.1:23792" default is "http://127.0.0.1:2379" /// public string? Endpoints { get; init; } /// - /// key path default is None + /// PEM client private key file used for mutual TLS. Must be configured together with `cert_path`. default is None /// public string? KeyPath { get; init; } /// diff --git a/bindings/java/src/main/java/org/apache/opendal/ServiceConfig.java b/bindings/java/src/main/java/org/apache/opendal/ServiceConfig.java index 036731a21490..448b999143d3 100644 --- a/bindings/java/src/main/java/org/apache/opendal/ServiceConfig.java +++ b/bindings/java/src/main/java/org/apache/opendal/ServiceConfig.java @@ -902,24 +902,28 @@ public Map configMap() { @RequiredArgsConstructor(access = AccessLevel.PRIVATE) class Etcd implements ServiceConfig { /** - *

certificate authority file path

+ *

PEM certificate authority file used to verify the server. + * Enables TLS independently of cert_path and key_path.

*

default is None

*/ public final String caPath; /** - *

cert path

+ *

PEM client certificate file used for mutual TLS. + * Must be configured together with key_path.

*

default is None

*/ public final String certPath; /** *

network address of the Etcd services. - * If use https, must set TLS options: ca_path, cert_path, key_path. + * Use HTTPS endpoints for TLS. Set ca_path to trust a custom certificate authority. + * Client authentication additionally requires both cert_path and key_path. * e.g. "127.0.0.1:23790,127.0.0.1:23791,127.0.0.1:23792" or "http://127.0.0.1:23790,http://127.0.0.1:23791,http://127.0.0.1:23792" or "https://127.0.0.1:23790,https://127.0.0.1:23791,https://127.0.0.1:23792"

*

default is "http://127.0.0.1:2379"

*/ public final String endpoints; /** - *

key path

+ *

PEM client private key file used for mutual TLS. + * Must be configured together with cert_path.

*

default is None

*/ public final String keyPath; diff --git a/core/services/etcd/src/backend.rs b/core/services/etcd/src/backend.rs index d199a17e0760..59883a033153 100644 --- a/core/services/etcd/src/backend.rs +++ b/core/services/etcd/src/backend.rs @@ -84,9 +84,12 @@ impl EtcdBuilder { self } - /// Set the certificate authority file path. + /// Set the PEM certificate authority file used to verify the server. /// - /// default is None + /// This enables TLS without requiring a client certificate or private key. + /// Use HTTPS endpoints when configuring TLS. + /// + /// No custom certificate authority is configured by default. pub fn ca_path(mut self, ca_path: &str) -> Self { if !ca_path.is_empty() { self.config.ca_path = Some(ca_path.to_string()) @@ -94,9 +97,12 @@ impl EtcdBuilder { self } - /// Set the certificate file path. + /// Set the PEM client certificate file used for mutual TLS. + /// + /// Set this together with [`Self::key_path`]. Building an operator with + /// only one of these paths returns [`ErrorKind::ConfigInvalid`]. /// - /// default is None + /// No client certificate is configured by default. pub fn cert_path(mut self, cert_path: &str) -> Self { if !cert_path.is_empty() { self.config.cert_path = Some(cert_path.to_string()) @@ -104,9 +110,12 @@ impl EtcdBuilder { self } - /// Set the key file path. + /// Set the PEM client private key file used for mutual TLS. /// - /// default is None + /// Set this together with [`Self::cert_path`]. Building an operator with + /// only one of these paths returns [`ErrorKind::ConfigInvalid`]. + /// + /// No client private key is configured by default. pub fn key_path(mut self, key_path: &str) -> Self { if !key_path.is_empty() { self.config.key_path = Some(key_path.to_string()) @@ -137,17 +146,28 @@ impl Builder for EtcdBuilder { let mut options = ConnectOptions::new(); - if self.config.ca_path.is_some() - && self.config.cert_path.is_some() - && self.config.key_path.is_some() - { - let ca = self.load_pem(self.config.ca_path.clone().unwrap().as_str())?; - let key = self.load_pem(self.config.key_path.clone().unwrap().as_str())?; - let cert = self.load_pem(self.config.cert_path.clone().unwrap().as_str())?; - - let tls_options = TlsOptions::default() - .ca_certificate(Certificate::from_pem(ca)) - .identity(Identity::from_pem(cert, key)); + if self.config.cert_path.is_some() != self.config.key_path.is_some() { + return Err(Error::new( + ErrorKind::ConfigInvalid, + "cert_path and key_path must be configured together", + ) + .with_operation("Builder::build") + .with_context("service", ETCD_SCHEME)); + } + + if self.config.ca_path.is_some() || self.config.cert_path.is_some() { + let mut tls_options = TlsOptions::default(); + if let Some(path) = &self.config.ca_path { + let ca = self.load_pem(path)?; + tls_options = tls_options.ca_certificate(Certificate::from_pem(ca)); + } + if let (Some(cert_path), Some(key_path)) = + (&self.config.cert_path, &self.config.key_path) + { + let cert = self.load_pem(cert_path)?; + let key = self.load_pem(key_path)?; + tls_options = tls_options.identity(Identity::from_pem(cert, key)); + } options = options.with_tls(tls_options); } @@ -178,6 +198,31 @@ impl EtcdBuilder { } } +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn incomplete_client_identity_is_rejected() { + for ca_path in [None, Some("ca.pem")] { + for (cert_path, key_path) in + [(Some("client.pem"), None), (None, Some("client-key.pem"))] + { + let config = EtcdConfig { + ca_path: ca_path.map(str::to_owned), + cert_path: cert_path.map(str::to_owned), + key_path: key_path.map(str::to_owned), + ..Default::default() + }; + let err = Operator::from_config(config).expect_err( + "incomplete client identity must fail before reading certificate files", + ); + assert_eq!(err.kind(), ErrorKind::ConfigInvalid); + } + } + } +} + #[derive(Debug, Clone)] pub struct EtcdBackend { pub(crate) core: Arc, diff --git a/core/services/etcd/src/config.rs b/core/services/etcd/src/config.rs index 4bf7ded0d920..6eda92ef3791 100644 --- a/core/services/etcd/src/config.rs +++ b/core/services/etcd/src/config.rs @@ -28,7 +28,8 @@ use super::backend::EtcdBuilder; #[non_exhaustive] pub struct EtcdConfig { /// network address of the Etcd services. - /// If use https, must set TLS options: `ca_path`, `cert_path`, `key_path`. + /// Use HTTPS endpoints for TLS. Set `ca_path` to trust a custom certificate authority. + /// Client authentication additionally requires both `cert_path` and `key_path`. /// e.g. "127.0.0.1:23790,127.0.0.1:23791,127.0.0.1:23792" or "http://127.0.0.1:23790,http://127.0.0.1:23791,http://127.0.0.1:23792" or "https://127.0.0.1:23790,https://127.0.0.1:23791,https://127.0.0.1:23792" /// /// default is "http://127.0.0.1:2379" @@ -45,15 +46,18 @@ pub struct EtcdConfig { /// /// default is "/" pub root: Option, - /// certificate authority file path + /// PEM certificate authority file used to verify the server. + /// Enables TLS independently of `cert_path` and `key_path`. /// /// default is None pub ca_path: Option, - /// cert path + /// PEM client certificate file used for mutual TLS. + /// Must be configured together with `key_path`. /// /// default is None pub cert_path: Option, - /// key path + /// PEM client private key file used for mutual TLS. + /// Must be configured together with `cert_path`. /// /// default is None pub key_path: Option, diff --git a/core/services/etcd/src/docs.md b/core/services/etcd/src/docs.md index d38ea007c017..a7bc8dd343f1 100644 --- a/core/services/etcd/src/docs.md +++ b/core/services/etcd/src/docs.md @@ -21,6 +21,8 @@ Use [`crate::EtcdConfig`] for serializable configuration and this builder's methods for direct construction. The field and method documentation defines accepted values, defaults, and environment interaction. +For server-authenticated TLS, configure an HTTPS endpoint and `ca_path`. The server certificate must be trusted by the supplied CA. For mutual TLS, also configure `cert_path` and `key_path`; these two paths must always be supplied together. + ## Example ### Via Builder diff --git a/fixtures/etcd/docker-compose-standalone-server-tls.yml b/fixtures/etcd/docker-compose-standalone-server-tls.yml new file mode 100644 index 000000000000..d10cdd4e84f0 --- /dev/null +++ b/fixtures/etcd/docker-compose-standalone-server-tls.yml @@ -0,0 +1,47 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +services: + etcd: + image: gcr.io/etcd-development/etcd:v3.6.4 + ports: + - "2379:2379" + volumes: + - ./ca.pem:/etc/etcd/certs/ca.pem:ro + - ./server.pem:/etc/etcd/certs/server.pem:ro + - ./server-key.pem:/etc/etcd/certs/server-key.pem:ro + command: + - /usr/local/bin/etcd + - --name=etcd + - --listen-client-urls=https://0.0.0.0:2379 + - --advertise-client-urls=https://127.0.0.1:2379 + - --max-request-bytes=10485760 + - --client-cert-auth=false + - --cert-file=/etc/etcd/certs/server.pem + - --key-file=/etc/etcd/certs/server-key.pem + healthcheck: + test: [ + "CMD", + "/usr/local/bin/etcdctl", + "endpoint", "health", + "--endpoints=https://127.0.0.1:2379", + "--cacert=/etc/etcd/certs/ca.pem" + ] + interval: 30s + timeout: 20s + retries: 5 + start_period: 40s diff --git a/website/data/services.json b/website/data/services.json index 50b778d526ab..d3aa21b40c95 100644 --- a/website/data/services.json +++ b/website/data/services.json @@ -1122,7 +1122,7 @@ "type": "string", "required": false, "group": "General", - "comments": "network address of the Etcd services.\nIf use https, must set TLS options: `ca_path`, `cert_path`, `key_path`.\ne.g. \"127.0.0.1:23790,127.0.0.1:23791,127.0.0.1:23792\" or \"http://127.0.0.1:23790,http://127.0.0.1:23791,http://127.0.0.1:23792\" or \"https://127.0.0.1:23790,https://127.0.0.1:23791,https://127.0.0.1:23792\"\n\ndefault is \"http://127.0.0.1:2379\"" + "comments": "network address of the Etcd services.\nUse HTTPS endpoints for TLS. Set `ca_path` to trust a custom certificate authority.\nClient authentication additionally requires both `cert_path` and `key_path`.\ne.g. \"127.0.0.1:23790,127.0.0.1:23791,127.0.0.1:23792\" or \"http://127.0.0.1:23790,http://127.0.0.1:23791,http://127.0.0.1:23792\" or \"https://127.0.0.1:23790,https://127.0.0.1:23791,https://127.0.0.1:23792\"\n\ndefault is \"http://127.0.0.1:2379\"" }, { "name": "username", @@ -1150,21 +1150,21 @@ "type": "string", "required": false, "group": "General", - "comments": "certificate authority file path\n\ndefault is None" + "comments": "PEM certificate authority file used to verify the server.\nEnables TLS independently of `cert_path` and `key_path`.\n\ndefault is None" }, { "name": "cert_path", "type": "string", "required": false, "group": "General", - "comments": "cert path\n\ndefault is None" + "comments": "PEM client certificate file used for mutual TLS.\nMust be configured together with `key_path`.\n\ndefault is None" }, { "name": "key_path", "type": "string", "required": false, "group": "General", - "comments": "key path\n\ndefault is None" + "comments": "PEM client private key file used for mutual TLS.\nMust be configured together with `cert_path`.\n\ndefault is None" }, { "name": "max_decoding_message_size", @@ -1179,31 +1179,31 @@ "binding": "rust", "language": "rust", "minimal": "use opendal::Operator;\n\nlet operator = Operator::via_iter(\"etcd\", [\n])?;", - "full": "use opendal::Operator;\n\nlet operator = Operator::via_iter(\"etcd\", [\n // network address of the Etcd services.\n // If use https, must set TLS options: `ca_path`, `cert_path`, `key_path`.\n // e.g. \"127.0.0.1:23790,127.0.0.1:23791,127.0.0.1:23792\" or \"http://127.0.0.1:23790,http://127.0.0.1:23791,http://127.0.0.1:23792\" or \"https://127.0.0.1:23790,https://127.0.0.1:23791,https://127.0.0.1:23792\"\n //\n // default is \"http://127.0.0.1:2379\"\n // (\"endpoints\".to_string(), \"...\".to_string()),\n\n // the username to connect etcd service.\n //\n // default is None\n // (\"username\".to_string(), \"...\".to_string()),\n\n // the password for authentication\n //\n // default is None\n // (\"password\".to_string(), \"...\".to_string()),\n\n // the working directory of the etcd service. Can be \"/path/to/dir\"\n //\n // default is \"/\"\n // (\"root\".to_string(), \"...\".to_string()),\n\n // certificate authority file path\n //\n // default is None\n // (\"ca_path\".to_string(), \"...\".to_string()),\n\n // cert path\n //\n // default is None\n // (\"cert_path\".to_string(), \"...\".to_string()),\n\n // key path\n //\n // default is None\n // (\"key_path\".to_string(), \"...\".to_string()),\n\n // the maximum size in bytes of a gRPC response that the etcd client decodes.\n //\n // Set this to read values larger than the etcd client's own limit. The etcd\n // server must also allow responses of that size.\n //\n // Refer to [`etcd_client::KvClient::max_decoding_message_size`](https://docs.rs/etcd-client/latest/etcd_client/struct.KvClient.html#method.max_decoding_message_size)\n //\n // default is None, which keeps the etcd client default of 4 MiB\n // (\"max_decoding_message_size\".to_string(), \"1000\".to_string()),\n])?;" + "full": "use opendal::Operator;\n\nlet operator = Operator::via_iter(\"etcd\", [\n // network address of the Etcd services.\n // Use HTTPS endpoints for TLS. Set `ca_path` to trust a custom certificate authority.\n // Client authentication additionally requires both `cert_path` and `key_path`.\n // e.g. \"127.0.0.1:23790,127.0.0.1:23791,127.0.0.1:23792\" or \"http://127.0.0.1:23790,http://127.0.0.1:23791,http://127.0.0.1:23792\" or \"https://127.0.0.1:23790,https://127.0.0.1:23791,https://127.0.0.1:23792\"\n //\n // default is \"http://127.0.0.1:2379\"\n // (\"endpoints\".to_string(), \"...\".to_string()),\n\n // the username to connect etcd service.\n //\n // default is None\n // (\"username\".to_string(), \"...\".to_string()),\n\n // the password for authentication\n //\n // default is None\n // (\"password\".to_string(), \"...\".to_string()),\n\n // the working directory of the etcd service. Can be \"/path/to/dir\"\n //\n // default is \"/\"\n // (\"root\".to_string(), \"...\".to_string()),\n\n // PEM certificate authority file used to verify the server.\n // Enables TLS independently of `cert_path` and `key_path`.\n //\n // default is None\n // (\"ca_path\".to_string(), \"...\".to_string()),\n\n // PEM client certificate file used for mutual TLS.\n // Must be configured together with `key_path`.\n //\n // default is None\n // (\"cert_path\".to_string(), \"...\".to_string()),\n\n // PEM client private key file used for mutual TLS.\n // Must be configured together with `cert_path`.\n //\n // default is None\n // (\"key_path\".to_string(), \"...\".to_string()),\n\n // the maximum size in bytes of a gRPC response that the etcd client decodes.\n //\n // Set this to read values larger than the etcd client's own limit. The etcd\n // server must also allow responses of that size.\n //\n // Refer to [`etcd_client::KvClient::max_decoding_message_size`](https://docs.rs/etcd-client/latest/etcd_client/struct.KvClient.html#method.max_decoding_message_size)\n //\n // default is None, which keeps the etcd client default of 4 MiB\n // (\"max_decoding_message_size\".to_string(), \"1000\".to_string()),\n])?;" }, { "binding": "java", "language": "java", "minimal": "import java.util.HashMap;\nimport java.util.Map;\nimport org.apache.opendal.Operator;\n\nMap config = new HashMap<>();\nOperator operator = Operator.of(\"etcd\", config);", - "full": "import java.util.HashMap;\nimport java.util.Map;\nimport org.apache.opendal.Operator;\n\nMap config = new HashMap<>();\n// network address of the Etcd services.\n// If use https, must set TLS options: `ca_path`, `cert_path`, `key_path`.\n// e.g. \"127.0.0.1:23790,127.0.0.1:23791,127.0.0.1:23792\" or \"http://127.0.0.1:23790,http://127.0.0.1:23791,http://127.0.0.1:23792\" or \"https://127.0.0.1:23790,https://127.0.0.1:23791,https://127.0.0.1:23792\"\n//\n// default is \"http://127.0.0.1:2379\"\n// config.put(\"endpoints\", \"...\");\n\n// the username to connect etcd service.\n//\n// default is None\n// config.put(\"username\", \"...\");\n\n// the password for authentication\n//\n// default is None\n// config.put(\"password\", \"...\");\n\n// the working directory of the etcd service. Can be \"/path/to/dir\"\n//\n// default is \"/\"\n// config.put(\"root\", \"...\");\n\n// certificate authority file path\n//\n// default is None\n// config.put(\"ca_path\", \"...\");\n\n// cert path\n//\n// default is None\n// config.put(\"cert_path\", \"...\");\n\n// key path\n//\n// default is None\n// config.put(\"key_path\", \"...\");\n\n// the maximum size in bytes of a gRPC response that the etcd client decodes.\n//\n// Set this to read values larger than the etcd client's own limit. The etcd\n// server must also allow responses of that size.\n//\n// Refer to [`etcd_client::KvClient::max_decoding_message_size`](https://docs.rs/etcd-client/latest/etcd_client/struct.KvClient.html#method.max_decoding_message_size)\n//\n// default is None, which keeps the etcd client default of 4 MiB\n// config.put(\"max_decoding_message_size\", \"1000\");\nOperator operator = Operator.of(\"etcd\", config);" + "full": "import java.util.HashMap;\nimport java.util.Map;\nimport org.apache.opendal.Operator;\n\nMap config = new HashMap<>();\n// network address of the Etcd services.\n// Use HTTPS endpoints for TLS. Set `ca_path` to trust a custom certificate authority.\n// Client authentication additionally requires both `cert_path` and `key_path`.\n// e.g. \"127.0.0.1:23790,127.0.0.1:23791,127.0.0.1:23792\" or \"http://127.0.0.1:23790,http://127.0.0.1:23791,http://127.0.0.1:23792\" or \"https://127.0.0.1:23790,https://127.0.0.1:23791,https://127.0.0.1:23792\"\n//\n// default is \"http://127.0.0.1:2379\"\n// config.put(\"endpoints\", \"...\");\n\n// the username to connect etcd service.\n//\n// default is None\n// config.put(\"username\", \"...\");\n\n// the password for authentication\n//\n// default is None\n// config.put(\"password\", \"...\");\n\n// the working directory of the etcd service. Can be \"/path/to/dir\"\n//\n// default is \"/\"\n// config.put(\"root\", \"...\");\n\n// PEM certificate authority file used to verify the server.\n// Enables TLS independently of `cert_path` and `key_path`.\n//\n// default is None\n// config.put(\"ca_path\", \"...\");\n\n// PEM client certificate file used for mutual TLS.\n// Must be configured together with `key_path`.\n//\n// default is None\n// config.put(\"cert_path\", \"...\");\n\n// PEM client private key file used for mutual TLS.\n// Must be configured together with `cert_path`.\n//\n// default is None\n// config.put(\"key_path\", \"...\");\n\n// the maximum size in bytes of a gRPC response that the etcd client decodes.\n//\n// Set this to read values larger than the etcd client's own limit. The etcd\n// server must also allow responses of that size.\n//\n// Refer to [`etcd_client::KvClient::max_decoding_message_size`](https://docs.rs/etcd-client/latest/etcd_client/struct.KvClient.html#method.max_decoding_message_size)\n//\n// default is None, which keeps the etcd client default of 4 MiB\n// config.put(\"max_decoding_message_size\", \"1000\");\nOperator operator = Operator.of(\"etcd\", config);" }, { "binding": "python", "language": "python", "minimal": "import opendal\n\noperator = opendal.Operator(\n \"etcd\",\n)", - "full": "import opendal\n\noperator = opendal.Operator(\n \"etcd\",\n # network address of the Etcd services.\n # If use https, must set TLS options: `ca_path`, `cert_path`, `key_path`.\n # e.g. \"127.0.0.1:23790,127.0.0.1:23791,127.0.0.1:23792\" or \"http://127.0.0.1:23790,http://127.0.0.1:23791,http://127.0.0.1:23792\" or \"https://127.0.0.1:23790,https://127.0.0.1:23791,https://127.0.0.1:23792\"\n #\n # default is \"http://127.0.0.1:2379\"\n # endpoints=\"...\",\n\n # the username to connect etcd service.\n #\n # default is None\n # username=\"...\",\n\n # the password for authentication\n #\n # default is None\n # password=\"...\",\n\n # the working directory of the etcd service. Can be \"/path/to/dir\"\n #\n # default is \"/\"\n # root=\"...\",\n\n # certificate authority file path\n #\n # default is None\n # ca_path=\"...\",\n\n # cert path\n #\n # default is None\n # cert_path=\"...\",\n\n # key path\n #\n # default is None\n # key_path=\"...\",\n\n # the maximum size in bytes of a gRPC response that the etcd client decodes.\n #\n # Set this to read values larger than the etcd client's own limit. The etcd\n # server must also allow responses of that size.\n #\n # Refer to [`etcd_client::KvClient::max_decoding_message_size`](https://docs.rs/etcd-client/latest/etcd_client/struct.KvClient.html#method.max_decoding_message_size)\n #\n # default is None, which keeps the etcd client default of 4 MiB\n # max_decoding_message_size=\"1000\",\n)" + "full": "import opendal\n\noperator = opendal.Operator(\n \"etcd\",\n # network address of the Etcd services.\n # Use HTTPS endpoints for TLS. Set `ca_path` to trust a custom certificate authority.\n # Client authentication additionally requires both `cert_path` and `key_path`.\n # e.g. \"127.0.0.1:23790,127.0.0.1:23791,127.0.0.1:23792\" or \"http://127.0.0.1:23790,http://127.0.0.1:23791,http://127.0.0.1:23792\" or \"https://127.0.0.1:23790,https://127.0.0.1:23791,https://127.0.0.1:23792\"\n #\n # default is \"http://127.0.0.1:2379\"\n # endpoints=\"...\",\n\n # the username to connect etcd service.\n #\n # default is None\n # username=\"...\",\n\n # the password for authentication\n #\n # default is None\n # password=\"...\",\n\n # the working directory of the etcd service. Can be \"/path/to/dir\"\n #\n # default is \"/\"\n # root=\"...\",\n\n # PEM certificate authority file used to verify the server.\n # Enables TLS independently of `cert_path` and `key_path`.\n #\n # default is None\n # ca_path=\"...\",\n\n # PEM client certificate file used for mutual TLS.\n # Must be configured together with `key_path`.\n #\n # default is None\n # cert_path=\"...\",\n\n # PEM client private key file used for mutual TLS.\n # Must be configured together with `cert_path`.\n #\n # default is None\n # key_path=\"...\",\n\n # the maximum size in bytes of a gRPC response that the etcd client decodes.\n #\n # Set this to read values larger than the etcd client's own limit. The etcd\n # server must also allow responses of that size.\n #\n # Refer to [`etcd_client::KvClient::max_decoding_message_size`](https://docs.rs/etcd-client/latest/etcd_client/struct.KvClient.html#method.max_decoding_message_size)\n #\n # default is None, which keeps the etcd client default of 4 MiB\n # max_decoding_message_size=\"1000\",\n)" }, { "binding": "nodejs", "language": "javascript", "minimal": "import { Operator } from \"opendal\";\n\nconst operator = new Operator(\"etcd\", {\n});", - "full": "import { Operator } from \"opendal\";\n\nconst operator = new Operator(\"etcd\", {\n // network address of the Etcd services.\n // If use https, must set TLS options: `ca_path`, `cert_path`, `key_path`.\n // e.g. \"127.0.0.1:23790,127.0.0.1:23791,127.0.0.1:23792\" or \"http://127.0.0.1:23790,http://127.0.0.1:23791,http://127.0.0.1:23792\" or \"https://127.0.0.1:23790,https://127.0.0.1:23791,https://127.0.0.1:23792\"\n //\n // default is \"http://127.0.0.1:2379\"\n // endpoints: \"...\",\n\n // the username to connect etcd service.\n //\n // default is None\n // username: \"...\",\n\n // the password for authentication\n //\n // default is None\n // password: \"...\",\n\n // the working directory of the etcd service. Can be \"/path/to/dir\"\n //\n // default is \"/\"\n // root: \"...\",\n\n // certificate authority file path\n //\n // default is None\n // ca_path: \"...\",\n\n // cert path\n //\n // default is None\n // cert_path: \"...\",\n\n // key path\n //\n // default is None\n // key_path: \"...\",\n\n // the maximum size in bytes of a gRPC response that the etcd client decodes.\n //\n // Set this to read values larger than the etcd client's own limit. The etcd\n // server must also allow responses of that size.\n //\n // Refer to [`etcd_client::KvClient::max_decoding_message_size`](https://docs.rs/etcd-client/latest/etcd_client/struct.KvClient.html#method.max_decoding_message_size)\n //\n // default is None, which keeps the etcd client default of 4 MiB\n // max_decoding_message_size: \"1000\",\n});" + "full": "import { Operator } from \"opendal\";\n\nconst operator = new Operator(\"etcd\", {\n // network address of the Etcd services.\n // Use HTTPS endpoints for TLS. Set `ca_path` to trust a custom certificate authority.\n // Client authentication additionally requires both `cert_path` and `key_path`.\n // e.g. \"127.0.0.1:23790,127.0.0.1:23791,127.0.0.1:23792\" or \"http://127.0.0.1:23790,http://127.0.0.1:23791,http://127.0.0.1:23792\" or \"https://127.0.0.1:23790,https://127.0.0.1:23791,https://127.0.0.1:23792\"\n //\n // default is \"http://127.0.0.1:2379\"\n // endpoints: \"...\",\n\n // the username to connect etcd service.\n //\n // default is None\n // username: \"...\",\n\n // the password for authentication\n //\n // default is None\n // password: \"...\",\n\n // the working directory of the etcd service. Can be \"/path/to/dir\"\n //\n // default is \"/\"\n // root: \"...\",\n\n // PEM certificate authority file used to verify the server.\n // Enables TLS independently of `cert_path` and `key_path`.\n //\n // default is None\n // ca_path: \"...\",\n\n // PEM client certificate file used for mutual TLS.\n // Must be configured together with `key_path`.\n //\n // default is None\n // cert_path: \"...\",\n\n // PEM client private key file used for mutual TLS.\n // Must be configured together with `cert_path`.\n //\n // default is None\n // key_path: \"...\",\n\n // the maximum size in bytes of a gRPC response that the etcd client decodes.\n //\n // Set this to read values larger than the etcd client's own limit. The etcd\n // server must also allow responses of that size.\n //\n // Refer to [`etcd_client::KvClient::max_decoding_message_size`](https://docs.rs/etcd-client/latest/etcd_client/struct.KvClient.html#method.max_decoding_message_size)\n //\n // default is None, which keeps the etcd client default of 4 MiB\n // max_decoding_message_size: \"1000\",\n});" }, { "binding": "go", "language": "go", "minimal": "import (\n\t\"github.com/apache/opendal-go-services/etcd\"\n\topendal \"github.com/apache/opendal/bindings/go\"\n)\n\noperator, err := opendal.NewOperator(etcd.Scheme, opendal.OperatorOptions{\n})", - "full": "import (\n\t\"github.com/apache/opendal-go-services/etcd\"\n\topendal \"github.com/apache/opendal/bindings/go\"\n)\n\noperator, err := opendal.NewOperator(etcd.Scheme, opendal.OperatorOptions{\n\t// network address of the Etcd services.\n\t// If use https, must set TLS options: `ca_path`, `cert_path`, `key_path`.\n\t// e.g. \"127.0.0.1:23790,127.0.0.1:23791,127.0.0.1:23792\" or \"http://127.0.0.1:23790,http://127.0.0.1:23791,http://127.0.0.1:23792\" or \"https://127.0.0.1:23790,https://127.0.0.1:23791,https://127.0.0.1:23792\"\n\t//\n\t// default is \"http://127.0.0.1:2379\"\n\t// \"endpoints\": \"...\",\n\n\t// the username to connect etcd service.\n\t//\n\t// default is None\n\t// \"username\": \"...\",\n\n\t// the password for authentication\n\t//\n\t// default is None\n\t// \"password\": \"...\",\n\n\t// the working directory of the etcd service. Can be \"/path/to/dir\"\n\t//\n\t// default is \"/\"\n\t// \"root\": \"...\",\n\n\t// certificate authority file path\n\t//\n\t// default is None\n\t// \"ca_path\": \"...\",\n\n\t// cert path\n\t//\n\t// default is None\n\t// \"cert_path\": \"...\",\n\n\t// key path\n\t//\n\t// default is None\n\t// \"key_path\": \"...\",\n\n\t// the maximum size in bytes of a gRPC response that the etcd client decodes.\n\t//\n\t// Set this to read values larger than the etcd client's own limit. The etcd\n\t// server must also allow responses of that size.\n\t//\n\t// Refer to [`etcd_client::KvClient::max_decoding_message_size`](https://docs.rs/etcd-client/latest/etcd_client/struct.KvClient.html#method.max_decoding_message_size)\n\t//\n\t// default is None, which keeps the etcd client default of 4 MiB\n\t// \"max_decoding_message_size\": \"1000\",\n})" + "full": "import (\n\t\"github.com/apache/opendal-go-services/etcd\"\n\topendal \"github.com/apache/opendal/bindings/go\"\n)\n\noperator, err := opendal.NewOperator(etcd.Scheme, opendal.OperatorOptions{\n\t// network address of the Etcd services.\n\t// Use HTTPS endpoints for TLS. Set `ca_path` to trust a custom certificate authority.\n\t// Client authentication additionally requires both `cert_path` and `key_path`.\n\t// e.g. \"127.0.0.1:23790,127.0.0.1:23791,127.0.0.1:23792\" or \"http://127.0.0.1:23790,http://127.0.0.1:23791,http://127.0.0.1:23792\" or \"https://127.0.0.1:23790,https://127.0.0.1:23791,https://127.0.0.1:23792\"\n\t//\n\t// default is \"http://127.0.0.1:2379\"\n\t// \"endpoints\": \"...\",\n\n\t// the username to connect etcd service.\n\t//\n\t// default is None\n\t// \"username\": \"...\",\n\n\t// the password for authentication\n\t//\n\t// default is None\n\t// \"password\": \"...\",\n\n\t// the working directory of the etcd service. Can be \"/path/to/dir\"\n\t//\n\t// default is \"/\"\n\t// \"root\": \"...\",\n\n\t// PEM certificate authority file used to verify the server.\n\t// Enables TLS independently of `cert_path` and `key_path`.\n\t//\n\t// default is None\n\t// \"ca_path\": \"...\",\n\n\t// PEM client certificate file used for mutual TLS.\n\t// Must be configured together with `key_path`.\n\t//\n\t// default is None\n\t// \"cert_path\": \"...\",\n\n\t// PEM client private key file used for mutual TLS.\n\t// Must be configured together with `cert_path`.\n\t//\n\t// default is None\n\t// \"key_path\": \"...\",\n\n\t// the maximum size in bytes of a gRPC response that the etcd client decodes.\n\t//\n\t// Set this to read values larger than the etcd client's own limit. The etcd\n\t// server must also allow responses of that size.\n\t//\n\t// Refer to [`etcd_client::KvClient::max_decoding_message_size`](https://docs.rs/etcd-client/latest/etcd_client/struct.KvClient.html#method.max_decoding_message_size)\n\t//\n\t// default is None, which keeps the etcd client default of 4 MiB\n\t// \"max_decoding_message_size\": \"1000\",\n})" } ] },