xclud / dart_kubernetes

Kubernetes client for Dart/Flutter.
https://pub.dev/packages/kubernetes
MIT License
14 stars 5 forks source link

CERTIFICATE_VERIFY_FAILED #3

Open Bast66 opened 12 months ago

Bast66 commented 12 months ago

Hi when connecting to a kubernetes cluster I use the client-certificate-data: from ~/.kube/config and get the following exception.

HandshakeException (HandshakeException: Handshake error in client (OS Error: CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate(handshake.cc:393)))

where I am supposed to install the certificate-authority-data: from ~/.kube/config ? Or is there an easier way to get this done?

Thanks. Bast

rohanmars commented 10 months ago

You can achieve this by parsing the kube config, something like:

      var kubeConfig = loadYaml(environment.apiConfig!);
      if (kubeConfig['kind'] == 'Config') {
        var currentContext = kubeConfig["current-context"];
        if (kubeConfig["contexts"] != null) {
          for (var context in kubeConfig["contexts"]) {
            if (context['name'] == currentContext) {
              var clusterName = context['context']['cluster'];
              // set namespace if not set
              var clusterNamespace = context['context']['namespace'];
              if (environment.namespace == null && clusterNamespace != null) {
                environment.namespace = clusterNamespace;
              }
              for (var cluster in kubeConfig['clusters']) {
                if (clusterName == cluster['name']) {
                  environment.apiUrl ??= cluster['cluster']['server'];
                  environment.apiClientCA ??=
                  cluster['cluster']['certificate-authority-data'];
                  break;
                }
              }

              var userName = context['context']['user'];
              for (var user in kubeConfig['users']) {
                if (userName == user['name']) {
                  environment.apiToken ??= user['user']['token'];
                  environment.apiClientCert ??=
                  user['user']['client-certificate-data'];
                  environment.apiClientKey ??= user['user']['client-key-data'];
                  break;
                }
              }
              break;
            }
          }
        }
      }

I'm using environment as a custom class to contain the kube cluster configuration.

Then in your client:

    if (environment.apiToken != null) {
      _kubernetesClient = KubernetesClient(
          serverUrl: environment.apiUrl!,
          accessToken: environment.apiToken!);
    } else if (environment.apiClientCert != null && environment.apiClientKey != null && environment.apiClientCA != null) {
      SecurityContext context = SecurityContext(withTrustedRoots: true);
      context.setTrustedCertificatesBytes(base64.decode(environment.apiClientCA!));
      context.useCertificateChainBytes(base64.decode(environment.apiClientCert!));
      context.usePrivateKeyBytes(base64.decode(environment.apiClientKey!));
      HttpClient httpClient = HttpClient(context: context);
      IOClient ioClient = IOClient(httpClient);

      _kubernetesClient = KubernetesClient(
          serverUrl: environment.apiUrl!,
          accessToken: '',
          httpClient: ioClient);
    }

I set the accessToken to '' in the client cert approach, the api should not probably make the accessToken required!

rohanmars commented 10 months ago

I noticed also there is a kubeconfig auth processor in the codebase (https://github.com/xclud/dart_kubernetes/blob/main/lib/src/config.dart) which could be used to parse the kubeconfig file and then setup the SecurityContext as above.

Bast66 commented 10 months ago

Thanks! Could something like this work also?

kubectl get secrets -o jsonpath="{.items[?(@.metadata.annotations['kubernetes.io/service-account.name']=='default')].data.token}"