oracle / oci-typescript-sdk

Oracle Cloud Infrastructure SDK for TypeScript and JavaScript
https://docs.oracle.com/en-us/iaas/Content/API/SDKDocs/typescriptsdk.htm
Other
68 stars 50 forks source link

oci ce cluster generate-token is missing in SDK #289

Open geisbruch opened 1 month ago

geisbruch commented 1 month ago

There is no option to generate OKE token to connect to the cluster without locally run "oci ce cluster generate-token"

geisbruch commented 1 month ago

Here an snippet about how to do it outside the SDK allowing a full kube config that does not requires oci cli to be installed in the machine

This snippet simulate the logic of the command oci ce cluster generate-token

const clusterId = "<your cluster id>";

const cred = new oci.SimpleAuthenticationDetailsProvider(
    "ocid1.tenancy.oc1..<your tenancy>",
    "ocid1.user.oc1..<your user>",
    "<your fingerprint>",
    "<your private key>",
    null,
    oci.common.Region.fromRegionId("<region id>")
);

function buildSignedUrl() {
      const method = "GET"; // Change this to POST, PUT, etc. if needed
      const endpoint = `https://containerengine.${cred.getRegion().regionId}.oraclecloud.com/cluster_request/${clusterId}`;
      const headersToSign = ["date", "(request-target)", "host"];
      //const keyId = "ocid1.tenancy.oc1..your_tenancy_ocid/ocid1.user.oc1..your_user_ocid/your_key_fingerprint";
      const keyId = `${cred.getTenantId()}/${cred.getUser()}/${cred.getFingerprint()}`;
      const privateKey = cred.getPrivateKey();

      // Prepare date header
      const date = new Date().toUTCString();

      // Parse the URL
      const url = new URL(endpoint);
      const host = url.host;
      const path = url.pathname;

      // Create (request-target) header
      const requestTarget = `${method.toLowerCase()} ${path}`;

      // Headers to sign
      const headers = {
          "date": date,
          "(request-target)": requestTarget,
          "host": host
      };

      // Create signing string
      const signingString = headersToSign.map((header) => `${header}: ${headers[header]}`).join("\n");

      // Sign the string
      const sign = crypto.createSign("RSA-SHA256");
      sign.update(signingString);
      sign.end();
      const signature = sign.sign(privateKey, "base64");

      // Create authorization header
      const authorizationHeader = `Signature algorithm="rsa-sha256",headers="${headersToSign.join(" ")}",keyId="${keyId}",signature="${signature}",version="1"`;

      // Construct the signed URL
      const signedUrl = `${url.href}?authorization=${encodeURIComponent(authorizationHeader)}&date=${encodeURIComponent(date)}`;
      return signedUrl;
}
const sUrl = buildSignedUrl();
const token = Buffer.from(sUrl).toString('base64');

Now you can use that token in your kubeconfig

  const ceClient = new oci.containerengine.ContainerEngineClient(
      {
          authenticationDetailsProvider: cred,
      }
  );
 const kcConfig = await ceClient.createKubeconfig({
      clusterId,
      createClusterKubeconfigContentDetails: {
          tokenVersion: "2.0.0"
      }
  });
  let kubeConfigStr = "";
  for await(const chunk of kcConfig.value) {
      kubeConfigStr += Buffer.from(chunk).toString("utf8");
  }

  const kubeConfigObj = yaml.parse(kubeConfigStr);
  const kc = new k8s.KubeConfig();
  kc.addCluster({
      name: kubeConfigObj.clusters[0].name,
      caData: kubeConfigObj.clusters[0].cluster["certificate-authority-data"],
      skipTLSVerify: true,
      server: kubeConfigObj.clusters[0].cluster.server
  });
  kc.addUser({
      token,
      name: kubeConfigObj.users[0].name
  });
  kc.addContext({
      cluster: kubeConfigObj.clusters[0].name,
      user: kubeConfigObj.users[0].name,
      name: kubeConfigObj.contexts[0].name
  });
  kc.setCurrentContext(kubeConfigObj.contexts[0].name);
  const k8sApi = kc.makeApiClient(k8s.CoreV1Api);
  const ns = await k8sApi.listNamespace();