HwangDongJun commented on issue #12711:
URL: https://github.com/apache/gluten/issues/12711#issuecomment-5275623199

   Hi, @zhouyuan 
   
   As suggested, I tried a code-level fix that doesn't require the CA-bundle 
symlink, and verified it with an A/B test under a reproducible hang condition.
   
   **TL;DR**: Using Gluten's existing mechanism for patching the Velox source 
at build time (`get-velox.sh` + a patch file, same pattern as 
`modify_arrow.patch`), I made Velox's S3 client read the CA bundle path from 
the `SSL_CERT_FILE` environment variable instead of relying solely on the 
hardcoded compile-time default.
   
   ## How we fixed it (patch ready, happy to upstream)
   
   Added a step to `ep/build-velox/src/get-velox.sh` to apply the patch below 
(right next to the existing step that applies `modify_arrow.patch`):
   
   ```diff
   diff --git a/ep/build-velox/src/get-velox.sh 
b/ep/build-velox/src/get-velox.sh
   index 5df0b0c28..d90d640ce 100755
   --- a/ep/build-velox/src/get-velox.sh
   +++ b/ep/build-velox/src/get-velox.sh
   @@ -162,6 +162,23 @@ function apply_compilation_fixes {
      git add 
${VELOX_HOME}/CMake/resolve_dependency_modules/arrow/modify_arrow.patch # to 
avoid the file from being deleted by git clean -dffx :/
    }
    
   +function apply_s3_ssl_ca_override_patch {
   +  pushd $VELOX_HOME
   +  (git apply --check ${CURRENT_DIR}/s3-ssl-ca-override.patch && \
   +   git apply ${CURRENT_DIR}/s3-ssl-ca-override.patch) || {
   +    echo "Failed to apply s3-ssl-ca-override.patch"
   +    exit 1
   +  }
   +  popd
   +}
   +
    function setup_linux {
      local LINUX_DISTRIBUTION=$(. /etc/os-release && echo ${ID})
      local LINUX_VERSION_ID=$(. /etc/os-release && echo ${VERSION_ID})
   @@ -242,6 +259,8 @@ fi
    
    apply_provided_velox_patch
    
   +apply_s3_ssl_ca_override_patch
   +
    apply_compilation_fixes
    
    echo "Finished getting Velox code"
   ```
   
   New `ep/build-velox/src/s3-ssl-ca-override.patch` (applied to two files 
under Velox's `velox/connectors/hive/storage_adapters/s3fs/`):
   
   ```diff
   --- a/velox/connectors/hive/storage_adapters/s3fs/S3Config.h
   +++ b/velox/connectors/hive/storage_adapters/s3fs/S3Config.h
   @@ -78,6 +78,7 @@
        kCredentialsProvider,
        kIMDSEnabled,
        kMultipartMinPartSize,
   +    kSSLCAFile,
        kEnd
      };
    
   @@ -119,6 +120,7 @@
                {Keys::kIMDSEnabled, std::make_pair("aws-imds-enabled", 
"true")},
                {Keys::kMultipartMinPartSize,
                 std::make_pair("min-part-size", "10MB")},
   +            {Keys::kSSLCAFile, std::make_pair("ssl.ca-file", std::nullopt)},
            };
        return config;
      }
   @@ -254,6 +256,15 @@
        return folly::to<bool>(value);
      }
    
   +  /// Custom CA bundle file path used to verify the S3 endpoint's TLS
   +  /// certificate, overriding the HTTP client's compiled-in default trust
   +  /// store location. If not set, S3FileSystem falls back to the
   +  /// SSL_CERT_FILE environment variable before using the compiled-in
   +  /// default.
   +  std::optional<std::string> sslCAFile() const {
   +    return config_.find(Keys::kSSLCAFile)->second;
   +  }
   +
      size_t minPartSize() const;
    
     private:
   --- a/velox/connectors/hive/storage_adapters/s3fs/S3FileSystem.cpp
   +++ b/velox/connectors/hive/storage_adapters/s3fs/S3FileSystem.cpp
   @@ -27,6 +27,7 @@
    
    #include <fmt/format.h>
    #include <glog/logging.h>
   +#include <cstdlib>
    #include <memory>
    #include <stdexcept>
    
   @@ -239,6 +240,25 @@
            Aws::Client::RequestChecksumCalculation::WHEN_REQUIRED;
        clientConfig.checksumConfig.responseChecksumValidation =
            Aws::Client::ResponseChecksumValidation::WHEN_REQUIRED;
   +
   +    // Allow overriding the TLS CA bundle used to verify S3 endpoints.
   +    // HTTP client libraries built via static toolchains (e.g. vcpkg) bake
   +    // in a compile-time default CA bundle path (for example the RHEL-family
   +    // path when built on Rocky/CentOS), which may not exist on a different
   +    // runtime OS (e.g. a Debian/Ubuntu container), causing TLS handshake
   +    // failures despite the system otherwise having a valid, working CA
   +    // bundle elsewhere. Prefer an explicit 'hive.s3.ssl.ca-file' config;
   +    // otherwise fall back to the widely-used SSL_CERT_FILE environment
   +    // variable convention (also respected by OpenSSL, the curl CLI,
   +    // Python, Node.js, etc.), so a runtime image only needs to set one
   +    // environment variable to point at its actual CA bundle location,
   +    // without requiring a Velox/Spark config change.
   +    if (s3Config_->sslCAFile().has_value()) {
   +      clientConfig.caFile = awsString(s3Config_->sslCAFile().value());
   +    } else if (const char* envCAFile = std::getenv("SSL_CERT_FILE")) {
   +      clientConfig.caFile = envCAFile;
   +    }
   +
        if (s3Config_->endpoint().has_value()) {
          clientConfig.endpointOverride = s3Config_->endpoint().value();
        }
   ```
   
   `caFile` is the officially supported AWS SDK C++ mechanism for this (it 
flows through to libcurl's `CURLOPT_CAINFO`). Users who don't touch either 
setting see no behavior change (`caFile` stays unset, same compiled-in default 
path as before).
   
   ## Verified
   
   Tested on a base image with no CA-bundle symlink at all, running a query 
that reads an Iceberg table on S3-compatible object storage with 
`batchscan=true`. Confirmed `numFallbackNodes == 0` (fully native execution) on 
every run, to make sure the comparison was actually exercising the native S3 
path (the code path touched by the patch above).
   
   With the identical patched build, identical query, and identical native 
execution plan, I toggled only the `SSL_CERT_FILE` environment variable and 
repeated each condition twice:
   
   - `SSL_CERT_FILE` set: completed normally within tens of seconds, every time
   - `SSL_CERT_FILE` unset (reproducing the original issue): hung for 240+ 
seconds with no error/exception, every time — matching the symptom described in 
this issue and #10670 exactly
   
   With `SSL_CERT_FILE` set, it was also noticeably faster than the non-native 
fallback (`batchscan=false`), comparable to or better than the speedup observed 
with the symlink workaround.
   
   ## Known limitations
   
   `hive.s3.ssl.ca-file` isn't wired into the `spark.hadoop.fs.s3a.*` → 
`hive.s3.*` passthrough yet (`cpp/velox/utils/ConfigExtractor.cc` on the Gluten 
side), so only the `SSL_CERT_FILE` environment variable path currently works 
(not a Spark config yet). Happy to add that if useful.
   
   Also, `SSL_CERT_FILE` was chosen because it's a widely-used convention in 
the OpenSSL/curl ecosystem, but that also means any deployment that already 
sets this variable for unrelated reasons could see a behavior change. Open to 
discussing whether a Gluten-specific name would be preferable.
   
   Happy to open a PR if there's interest.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to