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)
+}