minio / minio-cpp

MinIO C++ Client SDK for Amazon S3 Compatible Cloud Storage
https://minio-cpp.min.io/
Apache License 2.0
135 stars 56 forks source link

minio-cpp SDK Fails to Connect Without TLS in Docker Environment Due to curlpp Dependency on Windows 11 #170

Closed ucoruh closed 2 months ago

ucoruh commented 2 months ago

Issue Description

When using the minio-cpp SDK in a C++ application, we encountered an issue where the SDK, which relies on curlpp for HTTP requests, fails to connect to a MinIO server if TLS (SSL) is not configured. The problem arises because curlpp forces the connection to use TLS, and without a proper certificate setup, the connection either fails silently or provides uninformative error messages.

Root Cause:

The curlpp library enforces TLS by default, causing the connection to fail when attempting to connect to a MinIO server over HTTP without SSL. This results in issues where no meaningful error message is returned, making debugging difficult. When attempting to connect without SSL, curlpp still expects SSL-related configurations, leading to connection failures.


Solution

Steps Taken:

  1. Generate Self-Signed Certificates:

    • To resolve the issue, we generated self-signed SSL certificates and configured the MinIO server to use them.
    • These certificates were added to the Docker container running MinIO to ensure secure connections.
  2. Docker Setup with Self-Signed Certificates:

    • We configured Docker to use the self-signed certificates, enabling secure communication between the C++ application and the MinIO server.

docker-compose.yml

version: '3.7'

services:
  minio:
    image: minio/minio:latest
    container_name: minio
    ports:
      - "9000:9000"
      - "9001:9001"
    environment:
      MINIO_ACCESS_KEY: "admin"
      MINIO_SECRET_KEY: "adminadmin"
    volumes:
      - ./data:/data
      - ./certs:/root/.minio/certs
    command: server /data --console-address ":9001"
  1. Testing with awscurl:

    • We utilized the awscurl tool to test the connection with AWS Signature Version 4, ensuring that the self-signed certificates were correctly handled.
    • The self-signed certificate was added to the trusted root certificates on Windows to bypass SSL verification issues during testing.
  2. C++ Application Configuration:

    • The C++ application was modified to disable certificate checks and to ensure proper handling of self-signed certificates.
    • By configuring the MinIO client to ignore certificate checks and running with SSL enabled, the application was able to successfully connect to the MinIO server.

Step-by-Step Guide

1. Generate and Install Self-Signed Certificates

Open Command Prompt as Administrator:

This ensures that you have the necessary permissions to generate the files in the desired directory.

Navigate to the MinIO Directory:

cd C:\Tools\minio

Generate the Private Key:

openssl genrsa -out private.key 2048

Generate the Self-Signed Certificate:

openssl req -new -x509 
-key private.key 
-out public.crt 
-days 730 
-subj "/C=TR/ST=City/O=Coruh/OU=Coruh/CN=localhost"

Verify the Generated Files:

Ensure you have two files in C:\Tools\minio:

2. Add the Self-Signed Certificate to Trusted Certificates

Windows:

  1. Install the Certificate:

    • Open the public.crt file.
    • Click on "Install Certificate".
    • Choose to install it in the "Trusted Root Certification Authorities" store.
  2. Add the Certificate to the Python Certificate Store:

    • Append the public.crt content to the cacert.pem file located at C:\Python\Python312\Lib\site-packages\certifi\cacert.pem.

3. Testing the Setup

Install awscurl:

pip install awscurl

Make Requests Using awscurl:

awscurl --service s3 --access_key admin --secret_key adminadmin --insecure https://localhost:9000/

Example Code

Here’s an example of how the code was adapted to work with the configured SSL setup:

#include <miniocpp/client.h>
#include <iostream>

int main() {
    // MinIO connection setup
    minio::s3::BaseUrl base_url("https://localhost:9000");
    minio::creds::StaticProvider provider("admin", "adminadmin");
    minio::s3::Client client(base_url, &provider);

    // Disable certificate verification (for SSL)
    client.IgnoreCertCheck(true);

    // Attempt to list buckets
    minio::s3::ListBucketsResponse listResp = client.ListBuckets();

    // Check if the request was successful
    if (!listResp) {
        std::cerr << "Failed to connect to MinIO server: " << listResp.Error().String() << std::endl;
        return 1;
    }

    std::cout << "Buckets found on the server:" << std::endl;
    for (const auto& bucket : listResp.buckets) {
        std::cout << " - " << bucket.name << std::endl;
    }

    return 0;
}

Conclusion

By generating self-signed certificates, configuring Docker for SSL, and updating the C++ application to correctly handle SSL connections, we were able to overcome the limitations imposed by curlpp when using the minio-cpp SDK. This solution ensures that the connection works seamlessly with SSL, providing better security and error handling during development.

balamurugana commented 2 months ago

Have you tried https = false here with localhost:9000?

  explicit BaseUrl(std::string host, bool https = true,
                   std::string region = {});
ucoruh commented 2 months ago

No, I didn't notice this parameter before. I have removed all the certificates and related operations, and this parameter helped us disable HTTPS. Thank you for the tip.

The following code works well:

#include <miniocpp/client.h>
#include <iostream>

int main() {
    // MinIO connection setup
    minio::s3::BaseUrl base_url("http://localhost:9000",false);
    minio::creds::StaticProvider provider("admin", "adminadmin");
    minio::s3::Client client(base_url, &provider);

    // Debug modunu açma
    //client.Debug(true);

    // Sertifika doğrulama kontrolünü devre dışı bırakma (SSL kullanılmadığı için)
    //client.IgnoreCertCheck(true);

    // Bucket'ları listelemeye çalışma
    minio::s3::ListBucketsResponse listResp = client.ListBuckets();

    // İstek başarılı oldu mu kontrol et
    if (!listResp) {
        std::cerr << "Failed to connect to MinIO server: " << listResp.Error().String() << std::endl;
        return 1;
    }

    std::cout << "Buckets found on the server:" << std::endl;
    for (const auto& bucket : listResp.buckets) {
        std::cout << " - " << bucket.name << std::endl;
    }

    return 0;
}