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 <[email protected]>
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)
+}

Reply via email to