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

albumenj pushed a commit to branch refactor-with-go
in repository https://gitbox.apache.org/repos/asf/dubbo-admin.git


The following commit(s) were added to refs/heads/refactor-with-go by this push:
     new 50d8eab  Enhance ca (#988)
50d8eab is described below

commit 50d8eab14aae7b33d0f1fcbe1fa1ebff0743adaa
Author: Albumen Kevin <[email protected]>
AuthorDate: Wed Feb 22 10:01:45 2023 +0800

    Enhance ca (#988)
    
    * Enhance ca
    
    * Add license
---
 ca/cert/util.go                     | 101 ------------------
 ca/cmd/main.go                      |  54 ++++++++++
 ca/go.mod                           |   8 +-
 ca/go.sum                           |  40 +++++++-
 ca/main.go                          | 150 ---------------------------
 ca/pkg/cert/storage.go              |  52 ++++++++++
 ca/pkg/cert/util.go                 | 198 ++++++++++++++++++++++++++++++++++++
 ca/pkg/config/options.go            |  29 ++++++
 ca/{ => pkg}/k8s/client.go          |   0
 ca/pkg/security/server.go           | 126 +++++++++++++++++++++++
 ca/{ => pkg}/v1alpha1/ca.pb.go      |   0
 ca/{ => pkg}/v1alpha1/ca.proto      |   0
 ca/{ => pkg}/v1alpha1/ca_grpc.pb.go |   0
 ca/pkg/v1alpha1/ca_impl.go          |  48 +++++++++
 14 files changed, 552 insertions(+), 254 deletions(-)

diff --git a/ca/cert/util.go b/ca/cert/util.go
deleted file mode 100644
index 2d0baa0..0000000
--- a/ca/cert/util.go
+++ /dev/null
@@ -1,101 +0,0 @@
-// 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.
-
-package cert
-
-import (
-       "bytes"
-       "crypto/rand"
-       "crypto/rsa"
-       "crypto/x509"
-       "crypto/x509/pkix"
-       "encoding/pem"
-       "log"
-       "math/big"
-       "time"
-)
-
-func DecodeCert(cert string) *x509.Certificate {
-       block, _ := pem.Decode([]byte(cert))
-       p, err := x509.ParseCertificate(block.Bytes)
-       if err != nil {
-               log.Printf("Failed to parse public key. " + err.Error())
-               return nil
-       }
-       return p
-}
-
-func DecodePub(cert string) *rsa.PublicKey {
-       p, err := x509.ParsePKCS1PublicKey([]byte(cert))
-       if err != nil {
-               log.Printf("Failed to parse public key. " + err.Error())
-               return nil
-       }
-       return p
-}
-
-func DecodePri(cert string) *rsa.PrivateKey {
-       block, _ := pem.Decode([]byte(cert))
-
-       p, err := x509.ParsePKCS1PrivateKey(block.Bytes)
-       if err != nil {
-               log.Printf("Failed to parse private key. " + err.Error())
-               return nil
-       }
-       return p
-}
-
-func CreateCA() (*x509.Certificate, string, *rsa.PrivateKey) {
-       cert := &x509.Certificate{
-               SerialNumber: big.NewInt(2019),
-               Subject: pkix.Name{
-                       CommonName:   "Dubbo",
-                       Organization: []string{"Apache Dubbo"},
-               },
-               NotBefore:             time.Now(),
-               NotAfter:              time.Now().AddDate(1, 0, 0),
-               IsCA:                  true,
-               ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
-               KeyUsage:              x509.KeyUsageDigitalSignature | 
x509.KeyUsageCertSign,
-               BasicConstraintsValid: true,
-       }
-
-       caPrivKey, err := rsa.GenerateKey(rand.Reader, 4096)
-       if err != nil {
-               log.Fatal(err)
-       }
-
-       caBytes, err := x509.CreateCertificate(rand.Reader, cert, cert, 
&caPrivKey.PublicKey, caPrivKey)
-       if err != nil {
-               log.Fatal(err)
-       }
-
-       caPEM := new(bytes.Buffer)
-       pem.Encode(caPEM, &pem.Block{
-               Type:  "CERTIFICATE",
-               Bytes: caBytes,
-       })
-
-       return cert, caPEM.String(), caPrivKey
-}
-
-func EncodePri(caPrivKey *rsa.PrivateKey) string {
-       caPrivKeyPEM := new(bytes.Buffer)
-       pem.Encode(caPrivKeyPEM, &pem.Block{
-               Type:  "RSA PRIVATE KEY",
-               Bytes: x509.MarshalPKCS1PrivateKey(caPrivKey),
-       })
-       return caPrivKeyPEM.String()
-}
diff --git a/ca/cmd/main.go b/ca/cmd/main.go
new file mode 100644
index 0000000..c1706f1
--- /dev/null
+++ b/ca/cmd/main.go
@@ -0,0 +1,54 @@
+// 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.
+
+package main
+
+import (
+       "crypto/tls"
+       "github.com/apache/dubbo-admin/ca/pkg/cert"
+       "github.com/apache/dubbo-admin/ca/pkg/config"
+       "github.com/apache/dubbo-admin/ca/pkg/security"
+       "os"
+)
+
+// TODO read namespace from env
+const namespace = "dubbo-system"
+
+func main() {
+       // TODO read options from env
+       options := &config.Options{
+               EnableKubernetes: true,
+               Namespace:        namespace,
+               PlainServerPort:  30060,
+               SecureServerPort: 30062,
+               DebugPort:        30070,
+               CaValidity:       30 * 24 * 60 * 60 * 1000, // 30 day
+               CertValidity:     1 * 60 * 60 * 1000,       // 1 hour
+       }
+
+       s := &security.Server{
+               Options: options,
+               CertStorage: &cert.Storage{
+                       AuthorityCert: &cert.Cert{},
+                       ServerCerts:   map[string]*tls.Certificate{},
+               },
+       }
+
+       s.Init()
+       s.Start()
+
+       c := make(chan os.Signal)
+       <-c
+}
diff --git a/ca/go.mod b/ca/go.mod
index cfdecc3..72e60e6 100644
--- a/ca/go.mod
+++ b/ca/go.mod
@@ -19,6 +19,8 @@ module github.com/apache/dubbo-admin/ca
 go 1.19
 
 require (
+       github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
+       go.uber.org/zap v1.24.0
        google.golang.org/grpc v1.53.0
        google.golang.org/protobuf v1.28.1
        k8s.io/api v0.26.1
@@ -41,11 +43,15 @@ require (
        github.com/imdario/mergo v0.3.6 // indirect
        github.com/josharian/intern v1.0.0 // indirect
        github.com/json-iterator/go v1.1.12 // indirect
+       github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect
        github.com/mailru/easyjson v0.7.6 // indirect
        github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // 
indirect
        github.com/modern-go/reflect2 v1.0.2 // indirect
        github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 
indirect
+       github.com/sirupsen/logrus v1.4.2 // indirect
        github.com/spf13/pflag v1.0.5 // indirect
+       go.uber.org/atomic v1.10.0 // indirect
+       go.uber.org/multierr v1.9.0 // indirect
        golang.org/x/net v0.7.0 // indirect
        golang.org/x/oauth2 v0.4.0 // indirect
        golang.org/x/sys v0.5.0 // indirect
@@ -53,7 +59,7 @@ require (
        golang.org/x/text v0.7.0 // indirect
        golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
        google.golang.org/appengine v1.6.7 // indirect
-       google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44 // 
indirect
+       google.golang.org/genproto v0.0.0-20230221151758-ace64dc21148 // 
indirect
        gopkg.in/inf.v0 v0.9.1 // indirect
        gopkg.in/yaml.v2 v2.4.0 // indirect
        gopkg.in/yaml.v3 v3.0.1 // indirect
diff --git a/ca/go.sum b/ca/go.sum
index e28d113..6b9f5b1 100644
--- a/ca/go.sum
+++ b/ca/go.sum
@@ -1,7 +1,9 @@
 cloud.google.com/go v0.26.0/go.mod 
h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 github.com/BurntSushi/toml v0.3.1/go.mod 
h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/benbjohnson/clock v1.1.0 
h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod 
h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/client9/misspell v0.3.4/go.mod 
h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod 
h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
 github.com/creack/pty v1.1.9/go.mod 
h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/davecgh/go-spew v1.1.0/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 
h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -9,8 +11,12 @@ github.com/davecgh/go-spew v1.1.1/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
 github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod 
h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
 github.com/emicklei/go-restful/v3 v3.9.0 
h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE=
 github.com/emicklei/go-restful/v3 v3.9.0/go.mod 
h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod 
h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane 
v0.9.1-0.20191026205805-5f8ba28d4473/go.mod 
h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod 
h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod 
h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/go-kit/kit v0.9.0/go.mod 
h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.4.0/go.mod 
h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
 github.com/go-logr/logr v1.2.0/go.mod 
h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
 github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
 github.com/go-logr/logr v1.2.3/go.mod 
h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -22,6 +28,7 @@ github.com/go-openapi/jsonreference v0.20.0/go.mod 
h1:Ag74Ico3lPc+zR+qjn4XBUmXym
 github.com/go-openapi/swag v0.19.5/go.mod 
h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
 github.com/go-openapi/swag v0.19.14 
h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng=
 github.com/go-openapi/swag v0.19.14/go.mod 
h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
+github.com/go-stack/stack v1.8.0/go.mod 
h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2/go.mod 
h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod 
h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -29,6 +36,7 @@ github.com/golang/mock v1.1.1/go.mod 
h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
 github.com/golang/protobuf v1.2.0/go.mod 
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.1/go.mod 
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.2/go.mod 
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod 
h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
 github.com/golang/protobuf v1.4.0-rc.1/go.mod 
h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
 github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod 
h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
 github.com/golang/protobuf v1.4.0-rc.2/go.mod 
h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
@@ -50,6 +58,8 @@ github.com/google/go-cmp v0.5.9/go.mod 
h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
 github.com/google/gofuzz v1.0.0/go.mod 
h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
 github.com/google/gofuzz v1.1.0/go.mod 
h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 
h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
+github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod 
h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
 github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
 github.com/imdario/mergo v0.3.6/go.mod 
h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
 github.com/josharian/intern v1.0.0 
h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@@ -58,6 +68,10 @@ github.com/json-iterator/go v1.1.12 
h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
 github.com/json-iterator/go v1.1.12/go.mod 
h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/kisielk/errcheck v1.5.0/go.mod 
h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod 
h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod 
h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3 
h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod 
h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod 
h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
 github.com/kr/pretty v0.1.0/go.mod 
h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pretty v0.2.0/go.mod 
h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -79,19 +93,37 @@ github.com/niemeyer/pretty 
v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWb
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod 
h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/onsi/ginkgo/v2 v2.4.0 
h1:+Ig9nvqgS5OBSACXNk15PLdp0U9XPYROt9CFzVdFGIs=
 github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys=
+github.com/opentracing/opentracing-go v1.1.0/go.mod 
h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/pkg/errors v0.8.1/go.mod 
h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pmezard/go-difflib v1.0.0 
h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod 
h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod 
h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/sirupsen/logrus v1.4.2 
h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
+github.com/sirupsen/logrus v1.4.2/go.mod 
h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod 
h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/stoewer/go-strcase v1.2.0/go.mod 
h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
 github.com/stretchr/objx v0.1.0/go.mod 
h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod 
h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod 
h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod 
h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod 
h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.5.1/go.mod 
h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.6.1/go.mod 
h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0 
h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
 github.com/yuin/goldmark v1.1.27/go.mod 
h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod 
h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+go.uber.org/atomic v1.4.0/go.mod 
h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
+go.uber.org/atomic v1.10.0/go.mod 
h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
+go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
+go.uber.org/multierr v1.1.0/go.mod 
h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
+go.uber.org/multierr v1.9.0/go.mod 
h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
+go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod 
h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod 
h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod 
h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -123,6 +155,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod 
h1:RxMgew5VJxzue5/jJ
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -153,13 +186,16 @@ google.golang.org/appengine v1.6.7 
h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6
 google.golang.org/appengine v1.6.7/go.mod 
h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod 
h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod 
h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod 
h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod 
h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
 google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod 
h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44 
h1:EfLuoKW5WfkgVdDy7dTK8qSbH37AX5mj/MFh+bGPz14=
-google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod 
h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA=
+google.golang.org/genproto v0.0.0-20230221151758-ace64dc21148 
h1:muK+gVBJBfFb4SejshDBlN2/UgxCCOKH9Y34ljqEGOc=
+google.golang.org/genproto v0.0.0-20230221151758-ace64dc21148/go.mod 
h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw=
 google.golang.org/grpc v1.19.0/go.mod 
h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.23.0/go.mod 
h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod 
h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
 google.golang.org/grpc v1.27.0/go.mod 
h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.29.1/go.mod 
h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
 google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=
 google.golang.org/grpc v1.53.0/go.mod 
h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod 
h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
diff --git a/ca/main.go b/ca/main.go
deleted file mode 100644
index f3ff7eb..0000000
--- a/ca/main.go
+++ /dev/null
@@ -1,150 +0,0 @@
-// 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.
-package main
-
-import (
-       "bytes"
-       "context"
-       "crypto/rand"
-       "crypto/rsa"
-       "crypto/x509"
-       "encoding/pem"
-       "github.com/apache/dubbo-admin/ca/cert"
-       "github.com/apache/dubbo-admin/ca/k8s"
-       ca "github.com/apache/dubbo-admin/ca/v1alpha1"
-       "google.golang.org/grpc"
-       "log"
-       "math/big"
-       "net"
-       "os"
-       "time"
-)
-
-type DubboCertificateServiceServerImpl struct {
-       ca.UnimplementedDubboCertificateServiceServer
-
-       rootCert *x509.Certificate
-       pubKey   string
-       privKey  *rsa.PrivateKey
-}
-
-func (s *DubboCertificateServiceServerImpl) CreateCertificate(c 
context.Context, req *ca.DubboCertificateRequest) 
(*ca.DubboCertificateResponse, error) {
-       csr, _ := LoadCSR(req.Csr)
-       // TODO check server token
-       log.Printf("Receive csr request " + req.Csr)
-       csrTemplate := x509.Certificate{
-               Signature:          csr.Signature,
-               SignatureAlgorithm: csr.SignatureAlgorithm,
-
-               PublicKeyAlgorithm: csr.PublicKeyAlgorithm,
-               PublicKey:          csr.PublicKey,
-
-               SerialNumber: big.NewInt(2019),
-               Issuer:       s.rootCert.Subject,
-               Subject:      csr.Subject,
-               NotBefore:    time.Now(),
-               NotAfter:     time.Now().AddDate(0, 0, 1),
-               KeyUsage:     x509.KeyUsageDigitalSignature,
-               ExtKeyUsage:  []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
-       }
-       csrTemplate.DNSNames = csr.DNSNames
-
-       // TODO support ecdsa
-       result, err := x509.CreateCertificate(rand.Reader, &csrTemplate, 
s.rootCert, csrTemplate.PublicKey, s.privKey)
-       if err != nil {
-               log.Fatal(err)
-       }
-
-       pubPEM := new(bytes.Buffer)
-       pem.Encode(pubPEM, &pem.Block{
-               Type:  "CERTIFICATE",
-               Bytes: result,
-       })
-       pub := pubPEM.String()
-       log.Printf("Sign csr request " + pub)
-
-       puba := pub
-       return &ca.DubboCertificateResponse{
-               PublicKey:  puba,
-               TrustCerts: []string{s.pubKey},
-               ExpireTime: time.Now().AddDate(0, 0, 1).UnixMilli(),
-       }, nil
-}
-
-func LoadCSR(csrString string) (*x509.CertificateRequest, error) {
-       block, _ := pem.Decode([]byte(csrString))
-       csr, _ := x509.ParseCertificateRequest(block.Bytes)
-
-       return csr, nil
-}
-
-// TODO read namespace from env
-const namespace = "dubbo-system"
-
-func main() {
-       // TODO bypass k8s work
-       k8sClient := &k8s.Client{}
-       if !k8sClient.Init() {
-               log.Printf("Failed to create kuberentes client.")
-               return
-       }
-
-       // TODO inject pod based on Webhook
-
-       var caCert *x509.Certificate
-       var pub string
-       var pri *rsa.PrivateKey
-
-       certStr, priStr := k8sClient.GetCA(namespace)
-       if certStr != "" && priStr != "" {
-               caCert = cert.DecodeCert(certStr)
-               pri = cert.DecodePri(priStr)
-               pub = certStr
-       }
-       // TODO check cert if expired
-
-       if caCert == nil || pri == nil || pub == "" {
-               caCert, pub, pri = cert.CreateCA()
-       }
-
-       // TODO lock if multi server
-       k8sClient.UpdateCA(pub, cert.EncodePri(pri), namespace)
-
-       impl := &DubboCertificateServiceServerImpl{
-               rootCert: caCert,
-               pubKey:   pub,
-               privKey:  pri,
-       }
-
-       // TODO bind TLS server
-       grpcServer := grpc.NewServer()
-       ca.RegisterDubboCertificateServiceServer(grpcServer, impl)
-
-       lis, err := net.Listen("tcp", ":1234")
-       if err != nil {
-               log.Fatal(err)
-       }
-       go grpcServer.Serve(lis)
-
-       // TODO add task to update ca
-       log.Printf("Writing ca to config maps.")
-       if k8sClient.UpdateCAPub(pub) {
-               log.Printf("Write ca to config maps success.")
-       } else {
-               log.Printf("Write ca to config maps failed.")
-       }
-       c := make(chan os.Signal)
-       <-c
-}
diff --git a/ca/pkg/cert/storage.go b/ca/pkg/cert/storage.go
new file mode 100644
index 0000000..3e40158
--- /dev/null
+++ b/ca/pkg/cert/storage.go
@@ -0,0 +1,52 @@
+// 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.
+
+package cert
+
+import (
+       "crypto/rsa"
+       "crypto/tls"
+       "crypto/x509"
+       "time"
+)
+
+type Storage struct {
+       CaValidity   int64
+       CertValidity int64
+
+       RootCert      *Cert
+       AuthorityCert *Cert
+
+       ServerCerts map[string]*tls.Certificate
+}
+
+type Cert struct {
+       Cert       *x509.Certificate
+       CertPem    string
+       PrivateKey *rsa.PrivateKey
+}
+
+func (c *Cert) IsValid() bool {
+       if c.Cert == nil || c.CertPem == "" || c.PrivateKey == nil {
+               return false
+       }
+       if time.Now().Before(c.Cert.NotBefore) || 
time.Now().After(c.Cert.NotAfter) {
+               return false
+       }
+       if c.Cert.PublicKey == c.PrivateKey.Public() {
+               return false
+       }
+       return true
+}
diff --git a/ca/pkg/cert/util.go b/ca/pkg/cert/util.go
new file mode 100644
index 0000000..7aff7f8
--- /dev/null
+++ b/ca/pkg/cert/util.go
@@ -0,0 +1,198 @@
+// 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.
+
+package cert
+
+import (
+       "bytes"
+       "crypto/rand"
+       "crypto/rsa"
+       "crypto/x509"
+       "crypto/x509/pkix"
+       "encoding/pem"
+       "log"
+       "math/big"
+       "time"
+)
+
+func DecodeCert(cert string) *x509.Certificate {
+       block, _ := pem.Decode([]byte(cert))
+       p, err := x509.ParseCertificate(block.Bytes)
+       if err != nil {
+               log.Printf("Failed to parse public key. " + err.Error())
+               return nil
+       }
+       return p
+}
+
+func DecodePub(cert string) *rsa.PublicKey {
+       p, err := x509.ParsePKCS1PublicKey([]byte(cert))
+       if err != nil {
+               log.Printf("Failed to parse public key. " + err.Error())
+               return nil
+       }
+       return p
+}
+
+func DecodePri(cert string) *rsa.PrivateKey {
+       block, _ := pem.Decode([]byte(cert))
+
+       p, err := x509.ParsePKCS1PrivateKey(block.Bytes)
+       if err != nil {
+               log.Printf("Failed to parse private key. " + err.Error())
+               return nil
+       }
+       return p
+}
+
+func CreateCA(rootCert *Cert, caValidity int64) *Cert {
+       cert := &x509.Certificate{
+               SerialNumber: big.NewInt(2019),
+               Subject: pkix.Name{
+                       CommonName:   "Dubbo",
+                       Organization: []string{"Apache Dubbo"},
+               },
+               Issuer: pkix.Name{
+                       CommonName:   "Dubbo CA",
+                       Organization: []string{"Apache Dubbo"},
+               },
+               NotBefore:             time.Now(),
+               NotAfter:              time.Now().Add(time.Duration(caValidity) 
* time.Millisecond),
+               IsCA:                  true,
+               ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
+               KeyUsage:              x509.KeyUsageDigitalSignature | 
x509.KeyUsageCertSign,
+               BasicConstraintsValid: true,
+       }
+
+       caPrivKey, err := rsa.GenerateKey(rand.Reader, 4096)
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       caBytes, err := x509.CreateCertificate(rand.Reader, cert, cert, 
&caPrivKey.PublicKey, caPrivKey)
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       caPEM := new(bytes.Buffer)
+       err = pem.Encode(caPEM, &pem.Block{
+               Type:  "CERTIFICATE",
+               Bytes: caBytes,
+       })
+       if err != nil {
+               log.Printf("Failed to encode certificate. " + err.Error())
+               panic(err)
+       }
+
+       return &Cert{
+               Cert:       cert,
+               CertPem:    caPEM.String(),
+               PrivateKey: caPrivKey,
+       }
+}
+
+func SignServerCert(authorityCert *Cert, certValidity int64) (string, string) {
+       privKey, err := rsa.GenerateKey(rand.Reader, 4096)
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       cert := &x509.Certificate{
+               SerialNumber: big.NewInt(2019),
+               Issuer:       authorityCert.Cert.Subject,
+               Subject: pkix.Name{
+                       CommonName:   "Dubbo",
+                       Organization: []string{"Apache Dubbo"},
+               },
+               NotBefore:   time.Now(),
+               NotAfter:    time.Now().Add(time.Duration(certValidity) * 
time.Millisecond),
+               KeyUsage:    x509.KeyUsageDigitalSignature,
+               ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+       }
+       cert.DNSNames = []string{"localhost"}
+
+       c, err := x509.CreateCertificate(rand.Reader, cert, authorityCert.Cert, 
&privKey.PublicKey, authorityCert.PrivateKey)
+
+       certPem := new(bytes.Buffer)
+       err = pem.Encode(certPem, &pem.Block{
+               Type:  "CERTIFICATE",
+               Bytes: c,
+       })
+       if err != nil {
+               log.Printf("Failed to encode certificate. " + err.Error())
+               panic(err)
+       }
+       return certPem.String(), EncodePri(privKey)
+}
+
+func LoadCSR(csrString string) (*x509.CertificateRequest, error) {
+       block, _ := pem.Decode([]byte(csrString))
+       if block == nil {
+               return nil, nil
+       }
+       csr, err := x509.ParseCertificateRequest(block.Bytes)
+       if err != nil {
+               return nil, err
+       }
+
+       return csr, nil
+}
+
+func SignFromCSR(csr *x509.CertificateRequest, authorityCert *Cert, 
certValidity int64) (string, error) {
+       csrTemplate := x509.Certificate{
+               Signature:          csr.Signature,
+               SignatureAlgorithm: csr.SignatureAlgorithm,
+
+               PublicKeyAlgorithm: csr.PublicKeyAlgorithm,
+               PublicKey:          csr.PublicKey,
+
+               SerialNumber: big.NewInt(3),
+               Issuer:       authorityCert.Cert.Subject,
+               Subject:      csr.Subject,
+               NotBefore:    time.Now(),
+               NotAfter:     time.Now().Add(time.Duration(certValidity) * 
time.Millisecond),
+               KeyUsage:     x509.KeyUsageDigitalSignature,
+               ExtKeyUsage:  []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth | 
x509.ExtKeyUsageServerAuth},
+       }
+       csrTemplate.DNSNames = csr.DNSNames
+
+       // TODO support ecdsa
+       result, err := x509.CreateCertificate(rand.Reader, &csrTemplate, 
authorityCert.Cert, csrTemplate.PublicKey, authorityCert.PrivateKey)
+       if err != nil {
+               return "", err
+       }
+
+       pubPEM := new(bytes.Buffer)
+       err = pem.Encode(pubPEM, &pem.Block{
+               Type:  "CERTIFICATE",
+               Bytes: result,
+       })
+       if err != nil {
+               return "", err
+       }
+       pub := pubPEM.String()
+       log.Printf("Sign csr request " + pub)
+
+       return pub, nil
+}
+
+func EncodePri(caPrivKey *rsa.PrivateKey) string {
+       caPrivKeyPEM := new(bytes.Buffer)
+       pem.Encode(caPrivKeyPEM, &pem.Block{
+               Type:  "RSA PRIVATE KEY",
+               Bytes: x509.MarshalPKCS1PrivateKey(caPrivKey),
+       })
+       return caPrivKeyPEM.String()
+}
diff --git a/ca/pkg/config/options.go b/ca/pkg/config/options.go
new file mode 100644
index 0000000..2c3e8ed
--- /dev/null
+++ b/ca/pkg/config/options.go
@@ -0,0 +1,29 @@
+// 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.
+
+package config
+
+type Options struct {
+       EnableKubernetes bool
+
+       Namespace string
+
+       PlainServerPort  int
+       SecureServerPort int
+       DebugPort        int
+
+       CaValidity   int64
+       CertValidity int64
+}
diff --git a/ca/k8s/client.go b/ca/pkg/k8s/client.go
similarity index 100%
rename from ca/k8s/client.go
rename to ca/pkg/k8s/client.go
diff --git a/ca/pkg/security/server.go b/ca/pkg/security/server.go
new file mode 100644
index 0000000..db3b024
--- /dev/null
+++ b/ca/pkg/security/server.go
@@ -0,0 +1,126 @@
+// 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.
+
+package security
+
+import (
+       "crypto/tls"
+       "github.com/apache/dubbo-admin/ca/pkg/cert"
+       "github.com/apache/dubbo-admin/ca/pkg/config"
+       "github.com/apache/dubbo-admin/ca/pkg/k8s"
+       "github.com/apache/dubbo-admin/ca/pkg/v1alpha1"
+       "google.golang.org/grpc"
+       "google.golang.org/grpc/credentials"
+       "google.golang.org/grpc/reflection"
+       "log"
+       "net"
+       "strconv"
+)
+
+type Server struct {
+       Options     *config.Options
+       CertStorage *cert.Storage
+
+       KubeClient *k8s.Client
+
+       CertificateServer *v1alpha1.DubboCertificateServiceServerImpl
+       PlainServer       *grpc.Server
+       SecureServer      *grpc.Server
+}
+
+func (s *Server) Init() {
+       // TODO bypass k8s work
+       s.KubeClient = &k8s.Client{}
+       if !s.KubeClient.Init() {
+               panic("Failed to create kubernetes client.")
+       }
+
+       // TODO inject pod based on Webhook
+
+       // TODO Load root cert
+       certStr, priStr := s.KubeClient.GetCA(s.Options.Namespace)
+       if certStr != "" && priStr != "" {
+               s.CertStorage.AuthorityCert.Cert = cert.DecodeCert(certStr)
+               s.CertStorage.AuthorityCert.CertPem = certStr
+               s.CertStorage.AuthorityCert.PrivateKey = cert.DecodePri(priStr)
+       }
+       // TODO check cert if expired
+
+       if s.CertStorage.AuthorityCert.IsValid() {
+               s.CertStorage.AuthorityCert = 
cert.CreateCA(s.CertStorage.RootCert, s.Options.CaValidity)
+       }
+
+       // TODO lock if multi server
+       s.KubeClient.UpdateCA(s.CertStorage.AuthorityCert.CertPem, 
cert.EncodePri(s.CertStorage.AuthorityCert.PrivateKey), s.Options.Namespace)
+
+       impl := &v1alpha1.DubboCertificateServiceServerImpl{
+               Options:     s.Options,
+               CertStorage: s.CertStorage,
+       }
+
+       s.PlainServer = grpc.NewServer()
+       v1alpha1.RegisterDubboCertificateServiceServer(s.PlainServer, impl)
+       reflection.Register(s.PlainServer)
+
+       tlsConfig := &tls.Config{
+               GetCertificate: func(info *tls.ClientHelloInfo) 
(*tls.Certificate, error) {
+                       log.Printf("Get certificate for %s", info.ServerName)
+                       // TODO build cert in backend
+                       // TODO rotation cert
+                       // TODO create cert when start
+                       // TODO DNSName
+                       if s.CertStorage.ServerCerts[info.ServerName] == nil {
+                               serverCert, pri := 
cert.SignServerCert(s.CertStorage.AuthorityCert, s.Options.CertValidity)
+                               c, _ := tls.X509KeyPair([]byte(serverCert), 
[]byte(pri))
+                               s.CertStorage.ServerCerts[info.ServerName] = &c
+                       }
+                       return s.CertStorage.ServerCerts[info.ServerName], nil
+               },
+       }
+       s.SecureServer = 
grpc.NewServer(grpc.Creds(credentials.NewTLS(tlsConfig)))
+       v1alpha1.RegisterDubboCertificateServiceServer(s.SecureServer, impl)
+       reflection.Register(s.SecureServer)
+}
+
+func (s *Server) Start() {
+       lis, err := net.Listen("tcp", 
":"+strconv.Itoa(s.Options.PlainServerPort))
+       if err != nil {
+               log.Fatal(err)
+       }
+       go func() {
+               err := s.PlainServer.Serve(lis)
+               if err != nil {
+                       log.Fatal(err)
+               }
+       }()
+       lis, err = net.Listen("tcp", 
":"+strconv.Itoa(s.Options.SecureServerPort))
+       if err != nil {
+               log.Fatal(err)
+       }
+       go func() {
+               err := s.SecureServer.Serve(lis)
+               if err != nil {
+                       log.Fatal(err)
+               }
+       }()
+
+       // TODO add task to update ca
+       log.Printf("Writing ca to config maps.")
+       if s.KubeClient.UpdateCAPub(s.CertStorage.AuthorityCert.CertPem) {
+               log.Printf("Write ca to config maps success.")
+       } else {
+               log.Printf("Write ca to config maps failed.")
+       }
+}
diff --git a/ca/v1alpha1/ca.pb.go b/ca/pkg/v1alpha1/ca.pb.go
similarity index 100%
rename from ca/v1alpha1/ca.pb.go
rename to ca/pkg/v1alpha1/ca.pb.go
diff --git a/ca/v1alpha1/ca.proto b/ca/pkg/v1alpha1/ca.proto
similarity index 100%
rename from ca/v1alpha1/ca.proto
rename to ca/pkg/v1alpha1/ca.proto
diff --git a/ca/v1alpha1/ca_grpc.pb.go b/ca/pkg/v1alpha1/ca_grpc.pb.go
similarity index 100%
rename from ca/v1alpha1/ca_grpc.pb.go
rename to ca/pkg/v1alpha1/ca_grpc.pb.go
diff --git a/ca/pkg/v1alpha1/ca_impl.go b/ca/pkg/v1alpha1/ca_impl.go
new file mode 100644
index 0000000..5fa65bf
--- /dev/null
+++ b/ca/pkg/v1alpha1/ca_impl.go
@@ -0,0 +1,48 @@
+// 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.
+
+package v1alpha1
+
+import (
+       "context"
+       "github.com/apache/dubbo-admin/ca/pkg/cert"
+       "github.com/apache/dubbo-admin/ca/pkg/config"
+       "log"
+       "time"
+)
+
+type DubboCertificateServiceServerImpl struct {
+       UnimplementedDubboCertificateServiceServer
+       Options     *config.Options
+       CertStorage *cert.Storage
+}
+
+func (s *DubboCertificateServiceServerImpl) CreateCertificate(c 
context.Context, req *DubboCertificateRequest) (*DubboCertificateResponse, 
error) {
+       csr, _ := cert.LoadCSR(req.Csr)
+       // TODO check server token
+       log.Printf("Receive csr request " + req.Csr)
+       if csr == nil {
+               return &DubboCertificateResponse{}, nil
+       }
+       publicKey, err := cert.SignFromCSR(csr, s.CertStorage.AuthorityCert, 
s.Options.CertValidity)
+       if err != nil {
+               log.Fatal(err)
+       }
+       return &DubboCertificateResponse{
+               PublicKey:  publicKey,
+               TrustCerts: []string{s.CertStorage.AuthorityCert.CertPem},
+               ExpireTime: time.Now().AddDate(0, 0, 1).UnixMilli(),
+       }, nil
+}


Reply via email to