You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by zh...@apache.org on 2025/09/17 08:18:35 UTC

(dubbo-kubernetes) branch master updated: [aegis] add generator tools (#788)

This is an automated email from the ASF dual-hosted git repository.

zhongxjian pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/dubbo-kubernetes.git


The following commit(s) were added to refs/heads/master by this push:
     new 925a8a56 [aegis] add generator tools (#788)
925a8a56 is described below

commit 925a8a568a86ddc502fefdf525f5614cb28af819
Author: Jian Zhong <11...@qq.com>
AuthorDate: Wed Sep 17 16:18:31 2025 +0800

    [aegis] add generator tools (#788)
---
 README.md                            |   2 +-
 security/tools/generate_cert/main.go | 182 +++++++++++++++++++++++++++++++++++
 security/tools/generate_csr/main.go  |  68 +++++++++++++
 3 files changed, 251 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 249a9bd9..59ba4a1f 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@ Dubbo Kubernetes
 Provides support for building and deploying Dubbo applications in various environments, including Kubernetes and Alibaba Cloud ACK.
 
 ## Repositories
-The main code repositories of Dubbo on Kubernetes include:
+The main repositories of Dubbo on Kubernetes include:
 
 - **dubboctl** — The command-line management tool that provides control plane management, development framework scaffolding, and application deployment.
 - **dubbod** — The dubbo control plane. It is built on Istio to implement a proxyless service mesh and includes the following components:
diff --git a/security/tools/generate_cert/main.go b/security/tools/generate_cert/main.go
new file mode 100644
index 00000000..4dd9f90b
--- /dev/null
+++ b/security/tools/generate_cert/main.go
@@ -0,0 +1,182 @@
+/*
+ * 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.
+ */
+
+// Provide a tool to generate X.509 certificate with different options.
+
+package main
+
+import (
+	"crypto"
+	"crypto/x509"
+	"encoding/json"
+	"flag"
+	"fmt"
+	"log"
+	"os"
+	"os/exec"
+	"time"
+
+	k8s "k8s.io/api/core/v1"
+
+	"github.com/apache/dubbo-kubernetes/security/pkg/pki/ca"
+	"github.com/apache/dubbo-kubernetes/security/pkg/pki/util"
+)
+
+const (
+	// Layout for parsing time
+	timeLayout = "Jan 2 15:04:05 2006"
+
+	// modes supported by this tool.
+	selfSignedMode = "self-signed"
+	signerMode     = "signer"
+	citadelMode    = "citadel"
+)
+
+var (
+	host           = flag.String("host", "", "Comma-separated hostnames and IPs to generate a certificate for.")
+	validFrom      = flag.String("start-date", "", "Creation date in format of "+timeLayout)
+	validFor       = flag.Duration("duration", 10*365*24*time.Hour, "Duration that certificate is valid for.")
+	isCA           = flag.Bool("ca", false, "Whether this cert should be a Certificate Authority.")
+	signerCertFile = flag.String("signer-cert", "", "Signer certificate file (PEM encoded).")
+	signerPrivFile = flag.String("signer-priv", "", "Signer private key file (PEM encoded).")
+	isClient       = flag.Bool("client", false, "Whether this certificate is for a client.")
+	org            = flag.String("organization", "Juju org", "Organization for the cert.")
+	outCert        = flag.String("out-cert", "cert.pem", "Output certificate file.")
+	outPriv        = flag.String("out-priv", "priv.pem", "Output private key file.")
+	keySize        = flag.Int("key-size", 2048, "Size of the generated private key")
+	mode           = flag.String("mode", selfSignedMode, "Supported mode: self-signed, signer, citadel")
+	// Enable this flag if istio mTLS is enabled and the service is running as server side
+	isServer  = flag.Bool("server", false, "Whether this certificate is for a server.")
+	ec        = flag.String("ec-sig-alg", "", "Generate an elliptical curve private key with the specified algorithm")
+	curve     = flag.String("curve", "P256", "Specify the elliptic curve to use to generate an elliptical curve private key")
+	sanFields = flag.String("san", "", "Subject Alternative Names")
+)
+
+func checkCmdLine() {
+	flag.Parse()
+
+	hasCert, hasPriv := len(*signerCertFile) != 0, len(*signerPrivFile) != 0
+	switch *mode {
+	case selfSignedMode:
+		if hasCert || hasPriv {
+			log.Fatalf("--mode=%v is incompatible with --signer-cert or --signer-priv.", selfSignedMode)
+		}
+	case signerMode:
+		if !hasCert || !hasPriv {
+			log.Fatalf("Need --signer-cert and --signer-priv for --mode=%v.", signerMode)
+		}
+	case citadelMode:
+		if hasCert || hasPriv {
+			log.Fatalf("--mode=%v is incompatible with --signer-cert or --signer-priv.", citadelMode)
+		}
+	default:
+		log.Fatalf("Unsupported mode %v", *mode)
+	}
+}
+
+func saveCreds(certPem []byte, privPem []byte) {
+	err := os.WriteFile(*outCert, certPem, 0o644)
+	if err != nil {
+		log.Fatalf("Could not write output certificate: %s.", err)
+	}
+
+	err = os.WriteFile(*outPriv, privPem, 0o600)
+	if err != nil {
+		log.Fatalf("Could not write output private key: %s.", err)
+	}
+}
+
+func signCertFromCitadel() (*x509.Certificate, crypto.PrivateKey) {
+	args := []string{"get", "secret", "-n", "istio-system", "istio-ca-secret", "-o", "json"}
+	cmd := exec.Command("kubectl", args...)
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		log.Fatalf("Command failed error: %v\n, output\n%v\n", err, string(out))
+	}
+
+	var secret k8s.Secret
+	err = json.Unmarshal(out, &secret)
+	if err != nil {
+		log.Fatalf("Unmarshal secret error: %v", err)
+	}
+	key, err := util.ParsePemEncodedKey(secret.Data[ca.CAPrivateKeyFile])
+	if err != nil {
+		log.Fatalf("Unrecognized key format from citadel %v", err)
+	}
+	cert, err := util.ParsePemEncodedCertificate(secret.Data[ca.CACertFile])
+	if err != nil {
+		log.Fatalf("Unrecognized cert format from citadel %v", err)
+	}
+	return cert, key
+}
+
+func main() {
+	checkCmdLine()
+
+	var signerCert *x509.Certificate
+	var signerPriv crypto.PrivateKey
+	var err error
+	switch *mode {
+	case selfSignedMode:
+	case signerMode:
+		signerCert, signerPriv, err = util.LoadSignerCredsFromFiles(*signerCertFile, *signerPrivFile)
+		if err != nil {
+			log.Fatalf("Failed to load signer key cert from file: %v\n", err)
+		}
+	case citadelMode:
+		signerCert, signerPriv = signCertFromCitadel()
+	default:
+		log.Fatalf("Unsupported mode %v", *mode)
+	}
+
+	opts := util.CertOptions{
+		Host:         *host,
+		NotBefore:    getNotBefore(),
+		TTL:          *validFor,
+		SignerCert:   signerCert,
+		SignerPriv:   signerPriv,
+		Org:          *org,
+		IsCA:         *isCA,
+		IsSelfSigned: *mode == selfSignedMode,
+		IsClient:     *isClient,
+		RSAKeySize:   *keySize,
+		IsServer:     *isServer,
+		ECSigAlg:     util.SupportedECSignatureAlgorithms(*ec),
+		ECCCurve:     util.SupportedEllipticCurves(*curve),
+		DNSNames:     *sanFields,
+	}
+	certPem, privPem, err := util.GenCertKeyFromOptions(opts)
+	if err != nil {
+		log.Fatalf("Failed to generate certificate: %v\n", err)
+	}
+
+	saveCreds(certPem, privPem)
+	fmt.Printf("Certificate and private files successfully saved in %s and %s\n", *outCert, *outPriv)
+}
+
+func getNotBefore() time.Time {
+	if *validFrom == "" {
+		return time.Now()
+	}
+
+	t, err := time.Parse(timeLayout, *validFrom)
+	if err != nil {
+		log.Fatalf("Failed to parse the '-start-from' option as a time (error: %s)\n", err)
+	}
+
+	return t
+}
diff --git a/security/tools/generate_csr/main.go b/security/tools/generate_csr/main.go
new file mode 100644
index 00000000..a9ff6a2b
--- /dev/null
+++ b/security/tools/generate_csr/main.go
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+// Provide a tool to generate X.509 CSR with different options.
+
+package main
+
+import (
+	"flag"
+	"fmt"
+	"github.com/apache/dubbo-kubernetes/security/pkg/pki/util"
+	"k8s.io/klog/v2"
+	"os"
+)
+
+var (
+	host    = flag.String("host", "", "Comma-separated hostnames and IPs to generate a certificate for.")
+	org     = flag.String("organization", "Juju org", "Organization for the cert.")
+	outCsr  = flag.String("out-csr", "csr.pem", "Output csr file.")
+	outPriv = flag.String("out-priv", "priv.pem", "Output private key file.")
+	keySize = flag.Int("key-size", 2048, "Size of the generated private key")
+	ec      = flag.String("ec-sig-alg", "", "Generate an elliptical curve private key with the specified algorithm")
+	curve   = flag.String("curve", "P256", "Specify the elliptic curve to use to generate an elliptical curve private key")
+)
+
+func saveCreds(csrPem []byte, privPem []byte) {
+	err := os.WriteFile(*outCsr, csrPem, 0o644)
+	if err != nil {
+		klog.Errorf("Could not write output certificate request: %s.", err)
+	}
+
+	err = os.WriteFile(*outPriv, privPem, 0o600)
+	if err != nil {
+		klog.Errorf("Could not write output private key: %s.", err)
+	}
+}
+
+func main() {
+	flag.Parse()
+
+	csrPem, privPem, err := util.GenCSR(util.CertOptions{
+		Host:       *host,
+		Org:        *org,
+		RSAKeySize: *keySize,
+		ECSigAlg:   util.SupportedECSignatureAlgorithms(*ec),
+		ECCCurve:   util.SupportedEllipticCurves(*curve),
+	})
+	if err != nil {
+		klog.Errorf("Failed to generate CSR: %s.", err)
+	}
+
+	saveCreds(csrPem, privPem)
+	fmt.Printf("Certificate and private files successfully saved in %s and %s\n", *outCsr, *outPriv)
+}