From aa7fa6e467f5f26e3880b14d0177199f297fd933 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Fri, 10 Jun 2022 18:02:35 +0300 Subject: [PATCH 001/220] start work --- .gitignore | 16 +- go.mod | 58 +++++ go.sum | 334 +++++++++++++++++++++++++++++ internal/config/config.go | 10 + internal/controller/certificate.go | 48 +++++ internal/controller/controller.go | 74 +++++++ internal/controller/types.go | 7 + internal/vault/vault.go | 55 +++++ 8 files changed, 587 insertions(+), 15 deletions(-) create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/config/config.go create mode 100644 internal/controller/certificate.go create mode 100644 internal/controller/controller.go create mode 100644 internal/controller/types.go create mode 100644 internal/vault/vault.go diff --git a/.gitignore b/.gitignore index 66fd13c..b59f7e3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1 @@ -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib - -# Test binary, built with `go test -c` -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out - -# Dependency directories (remove the comment below to include it) -# vendor/ +test/ \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..f659b71 --- /dev/null +++ b/go.mod @@ -0,0 +1,58 @@ +module github.com/terra-cube/key-keeper + +go 1.18 + +require ( + github.com/hashicorp/vault/api v1.7.1 + github.com/stretchr/testify v1.7.0 +) + +require ( + github.com/armon/go-metrics v0.3.9 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/cenkalti/backoff/v3 v3.0.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fatih/color v1.7.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v0.16.2 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.3 // indirect + github.com/hashicorp/go-retryablehttp v0.6.6 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.2 // indirect + github.com/hashicorp/go-version v1.2.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/hashicorp/vault/sdk v0.5.0 // indirect + github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect + github.com/mattn/go-colorable v0.1.6 // indirect + github.com/mattn/go-isatty v0.0.12 // indirect + github.com/mitchellh/copystructure v1.0.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.0.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.0 // indirect + github.com/oklog/run v1.0.0 // indirect + github.com/pierrec/lz4 v2.5.2+incompatible // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect + golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 // indirect + golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect + golang.org/x/text v0.3.3 // indirect + golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 // indirect + google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect + google.golang.org/grpc v1.41.0 // indirect + google.golang.org/protobuf v1.26.0 // indirect + gopkg.in/square/go-jose.v2 v2.5.1 // indirect + gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..f73879f --- /dev/null +++ b/go.sum @@ -0,0 +1,334 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/armon/go-metrics v0.3.9 h1:O2sNqxBdvq8Eq5xmzljcYzAORli6RWCvEym4cJf9m18= +github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= +github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +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/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +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= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +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/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch/v5 v5.5.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y= +github.com/frankban/quicktest v1.13.0 h1:yNZif1OkDfNoDfb9zZa9aXIpejNR4F23Wely0c+Qdqk= +github.com/frankban/quicktest v1.13.0/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/r/VLSOOIySU= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-ldap/ldap/v3 v3.1.10/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= +github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +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.3.4/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= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.16.2 h1:K4ev2ib4LdQETX5cSZBG0DVLk1jwGqSPXBjdah3veNs= +github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy v0.1.0/go.mod h1:d1g9WGtAunDNpek8jUIEJnBlbgKS1N2Q61QkHiZyR1g= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.3 h1:DXmvivbWD5qdiBts9TpBC7BYL1Aia5sxbRgQB+v6UZM= +github.com/hashicorp/go-plugin v1.4.3/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM= +github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.1/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 h1:cCRo8gK7oq6A2L6LICkUZ+/a5rLiRXFMf1Qd4xSwxTc= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.1/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.5/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 h1:om4Al8Oy7kCm/B86rLCLah4Dt5Aa0Fr5rYBG60OzwHQ= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/vault/api v1.7.1 h1:uUpxcZO3XV1Sb96dEtT+tZlSpV7U/zEi0NoksM7lU5M= +github.com/hashicorp/vault/api v1.7.1/go.mod h1:TlKWwxZySuDARVFz/H0sf6rgWddIlX4t4DO9baT2nXc= +github.com/hashicorp/vault/sdk v0.5.0 h1:EED7p0OCU3OY5SAqJwSANofY1YKMytm+jDHDQ2EzGVQ= +github.com/hashicorp/vault/sdk v0.5.0/go.mod h1:UJZHlfwj7qUJG8g22CuxUgkdJouFrBNvBHCyx8XAPdo= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/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/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pierrec/lz4 v2.5.2+incompatible h1:WCjObylUIOlKy/+7Abdn34TLIkXiA4UWUMhxq9m9ZXI= +github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= +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.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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-20190222072716-a9d3bda3a223/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-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +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-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +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.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.41.0 h1:f+PlOh7QV4iIJkPrx5NQ7qaNGFQ3OTse67yaDHfju4E= +google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 0000000..4ac6fb4 --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,10 @@ +package config + +type Configuration struct { + BaseDomain string `yaml:"base_domain"` + Certificates []Certificate `yaml:"certificates"` +} + +type Certificate struct{ + +} \ No newline at end of file diff --git a/internal/controller/certificate.go b/internal/controller/certificate.go new file mode 100644 index 0000000..b8f2abf --- /dev/null +++ b/internal/controller/certificate.go @@ -0,0 +1,48 @@ +package controller + +import ( + "crypto/tls" + "crypto/x509" + "fmt" + "os" +) + +func (s *controller) storeCertificate(domain string, cert, key []byte) error { + err := os.WriteFile(s.certPath, cert, 0644) + if err != nil { + return fmt.Errorf("failed to save certificate for domain %s: %w", domain, err) + } + + err = os.WriteFile(s.keyPath, key, 0600) + if err != nil { + return fmt.Errorf("failed to save key file: %w", err) + } + + return nil +} + +func (s *controller) readCertificate(domain string) (*tls.Certificate, error) { + crtContent, err := os.ReadFile(s.certPath) + if err != nil { + return nil, err + } + + keyContent, err := os.ReadFile(s.keyPath) + if err != nil { + return nil, err + } + + cert, err := tls.X509KeyPair(crtContent, keyContent) + if err != nil { + return nil, fmt.Errorf("failed to parse x509 key pair: %w", err) + } + if len(cert.Certificate) == 0 { + return nil, fmt.Errorf("list of certificates is empty") + } + + cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0]) + if err != nil { + return nil, err + } + return &cert, nil +} diff --git a/internal/controller/controller.go b/internal/controller/controller.go new file mode 100644 index 0000000..ae6fed8 --- /dev/null +++ b/internal/controller/controller.go @@ -0,0 +1,74 @@ +package controller + +import ( + "context" + "os" + "time" +) + +type store interface { + Write(ctx context.Context, path string, data map[string]interface{}) (map[string]interface{}, error) + Read(ctx context.Context, path string) (map[string]interface{}, error) + List(ctx context.Context, path string) (map[string]interface{}, error) +} + +type controller struct { + store store + + commonName string + domain string + storeCAPath string + storeTimeout time.Duration + + certPath string + keyPath string + caPath string + + validInterval time.Duration +} + +func New(store store, cfg Config) (*controller, error) { + c := &controller{ + store: store, + commonName: cfg.CommonName, + storeCAPath: cfg.VaultCAPath, + } + + return c, nil +} + +func (s *controller) TurnOn() error { + cert, err := s.readCertificate(s.domain) + if time.Until(cert.Leaf.NotAfter) > s.validInterval { + return nil + } + if err != nil && !os.IsNotExist(err) { + return err + } + + ctx, cancel := context.WithTimeout(context.Background(), s.storeTimeout) + defer cancel() + err = s.GenerateCA(ctx) + if err != nil { + return err + } + + return nil +} + +func (s *controller) GenerateCA(ctx context.Context) error { + caData := map[string]interface{}{ + "common_name": s.commonName, + "ttl": "8760h", + } + caCert, err := s.store.Write(ctx, "pki/root/generate/internal", caData) + if err != nil { + return err + } + if len(caCert) == 0 { + return nil + } + + _, err = s.store.Write(ctx, s.storeCAPath, caCert) + return err +} diff --git a/internal/controller/types.go b/internal/controller/types.go new file mode 100644 index 0000000..c488b85 --- /dev/null +++ b/internal/controller/types.go @@ -0,0 +1,7 @@ +package controller + +type Config struct { + CommonName string + + VaultCAPath string +} diff --git a/internal/vault/vault.go b/internal/vault/vault.go new file mode 100644 index 0000000..f185c05 --- /dev/null +++ b/internal/vault/vault.go @@ -0,0 +1,55 @@ +package vault + +import ( + "context" + "net/http" + "time" + + "github.com/hashicorp/vault/api" +) + +type vault struct { + cli *api.Client +} + +func New(addr, token string) (*vault, error) { + httpClient := &http.Client{ + Timeout: 10 * time.Second, + } + + client, err := api.NewClient( + &api.Config{ + Address: addr, + HttpClient: httpClient, + }, + ) + client.SetToken(token) + + return &vault{ + cli: client, + }, err +} + +func (c *vault) List(ctx context.Context, path string) (map[string]interface{}, error) { + s, err := c.cli.Logical().ListWithContext(ctx, path) + if s != nil { + return s.Data, err + } + return nil, err +} + +func (c *vault) Read(ctx context.Context, path string) (map[string]interface{}, error) { + s, err := c.cli.Logical().ReadWithContext(ctx, path) + if s != nil { + return s.Data, err + } + return nil, err +} + +func (c *vault) Write(ctx context.Context, path string, data map[string]interface{}) (map[string]interface{}, error) { + s, err := c.cli.Logical().WriteWithContext(ctx, path, data) + if s != nil { + return s.Data, err + } + return nil, err +} From 1276a5e3774eb639f35882e67ec3d2a453aeaa2b Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 13 Jun 2022 15:16:18 +0300 Subject: [PATCH 002/220] add getting all certs --- go.mod | 8 +- go.sum | 32 ++++++- internal/controller/certificate.go | 14 +-- internal/controller/controller.go | 146 +++++++++++++++++++++++------ internal/controller/types.go | 16 +++- 5 files changed, 171 insertions(+), 45 deletions(-) diff --git a/go.mod b/go.mod index f659b71..7c71731 100644 --- a/go.mod +++ b/go.mod @@ -4,14 +4,13 @@ go 1.18 require ( github.com/hashicorp/vault/api v1.7.1 - github.com/stretchr/testify v1.7.0 + go.uber.org/zap v1.21.0 ) require ( github.com/armon/go-metrics v0.3.9 // indirect github.com/armon/go-radix v1.0.0 // indirect github.com/cenkalti/backoff/v3 v3.0.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect github.com/fatih/color v1.7.0 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.4 // indirect @@ -42,11 +41,11 @@ require ( github.com/mitchellh/reflectwalk v1.0.0 // indirect github.com/oklog/run v1.0.0 // indirect github.com/pierrec/lz4 v2.5.2+incompatible // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.6.0 // indirect golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect - golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 // indirect + golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect golang.org/x/text v0.3.3 // indirect golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 // indirect @@ -54,5 +53,4 @@ require ( google.golang.org/grpc v1.41.0 // indirect google.golang.org/protobuf v1.26.0 // indirect gopkg.in/square/go-jose.v2 v2.5.1 // indirect - gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect ) diff --git a/go.sum b/go.sum index f73879f..f1270ec 100644 --- a/go.sum +++ b/go.sum @@ -12,6 +12,8 @@ github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -193,6 +195,7 @@ github.com/pierrec/lz4 v2.5.2+incompatible h1:WCjObylUIOlKy/+7Abdn34TLIkXiA4UWUM github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -225,11 +228,20 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 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= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -237,6 +249,8 @@ golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -246,9 +260,11 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -256,6 +272,7 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -270,6 +287,8 @@ golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -284,6 +303,10 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -319,7 +342,7 @@ google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/l google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= @@ -328,7 +351,10 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/controller/certificate.go b/internal/controller/certificate.go index b8f2abf..a6beb63 100644 --- a/internal/controller/certificate.go +++ b/internal/controller/certificate.go @@ -7,17 +7,17 @@ import ( "os" ) -func (s *controller) storeCertificate(domain string, cert, key []byte) error { - err := os.WriteFile(s.certPath, cert, 0644) - if err != nil { - return fmt.Errorf("failed to save certificate for domain %s: %w", domain, err) +func (s *controller) storeCertificate(path string, cert []byte) error { + if err := os.WriteFile(path, cert, 0644); err != nil { + return fmt.Errorf("failed to save certificate with path %s: %w", path, err) } + return nil +} - err = os.WriteFile(s.keyPath, key, 0600) - if err != nil { +func (s *controller) storeKey(path string, key []byte) error { + if err := os.WriteFile(path, key, 0600); err != nil { return fmt.Errorf("failed to save key file: %w", err) } - return nil } diff --git a/internal/controller/controller.go b/internal/controller/controller.go index ae6fed8..abd483f 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -2,10 +2,15 @@ package controller import ( "context" + "fmt" "os" "time" + + "go.uber.org/zap" ) +var intermediateCommonNameLayout = "%s Intermediate Authority" + type store interface { Write(ctx context.Context, path string, data map[string]interface{}) (map[string]interface{}, error) Read(ctx context.Context, path string) (map[string]interface{}, error) @@ -15,31 +20,37 @@ type store interface { type controller struct { store store - commonName string - domain string - storeCAPath string - storeTimeout time.Duration - - certPath string - keyPath string - caPath string - - validInterval time.Duration + commonName string + domainName string + storeIntermediateCAPath string + storeCertPath string + storeTimeout time.Duration + certPath string + keyPath string + caPath string + validInterval time.Duration } -func New(store store, cfg Config) (*controller, error) { +func New(store store, cfg Config) *controller { c := &controller{ - store: store, - commonName: cfg.CommonName, - storeCAPath: cfg.VaultCAPath, - } + store: store, - return c, nil + commonName: cfg.CommonName, + domainName: cfg.DomainName, + storeIntermediateCAPath: cfg.VaultCertPath, + storeCertPath: cfg.VaultCertPath, + storeTimeout: cfg.VaultTimeout, + certPath: cfg.CertPath, + keyPath: cfg.KeyPath, + caPath: cfg.CaPath, + validInterval: cfg.ValidInterval, + } + return c } func (s *controller) TurnOn() error { - cert, err := s.readCertificate(s.domain) - if time.Until(cert.Leaf.NotAfter) > s.validInterval { + cert, err := s.readCertificate(s.domainName) + if cert != nil && time.Until(cert.Leaf.NotAfter) > s.validInterval { return nil } if err != nil && !os.IsNotExist(err) { @@ -48,27 +59,106 @@ func (s *controller) TurnOn() error { ctx, cancel := context.WithTimeout(context.Background(), s.storeTimeout) defer cancel() - err = s.GenerateCA(ctx) + + intermediateCA, err := s.GenerateIntermediateCA(ctx) if err != nil { return err } + if err := s.storeCertificate(s.caPath, intermediateCA); err != nil { + return err + } + + ctx, cancel = context.WithTimeout(context.Background(), s.storeTimeout) + defer cancel() + + certData, keyData, err := s.GenerateCert(ctx) + if err != nil { + return err + } + if err := s.storeCertificate(s.certPath, certData); err != nil { + return err + } + if err := s.storeKey(s.keyPath, keyData); err != nil { + return err + } + go s.runtime() return nil } -func (s *controller) GenerateCA(ctx context.Context) error { - caData := map[string]interface{}{ - "common_name": s.commonName, +func (s *controller) GenerateIntermediateCA(ctx context.Context) ([]byte, error) { + cert, _ := s.store.Read(ctx, s.storeIntermediateCAPath) + if cert != nil { + return cert["certificate"].([]byte), nil + } + + //TODO: check expire + csrData := map[string]interface{}{ + "common_name": fmt.Sprintf(intermediateCommonNameLayout, s.commonName), "ttl": "8760h", } - caCert, err := s.store.Write(ctx, "pki/root/generate/internal", caData) + csr, err := s.store.Write(ctx, "pki_int/intermediate/generate/internal", csrData) if err != nil { - return err + return nil, err } - if len(caCert) == 0 { - return nil + + pemData := map[string]interface{}{ + "csr": csr["csr"], + "format": "pem_bundle", + "ttl": "8760h", + } + pem, err := s.store.Write(ctx, "pki/root/sign-intermediate", pemData) + if err != nil { + return nil, err + } + + certData := map[string]interface{}{ + "certificate": pem["certificate"], + } + if _, err = s.store.Write(ctx, "pki_int/intermediate/set-signed", certData); err != nil { + return nil, err } - _, err = s.store.Write(ctx, s.storeCAPath, caCert) - return err + if _, err = s.store.Write(ctx, s.storeIntermediateCAPath, pem); err != nil { + return nil, err + } + return pem["certificate"].([]byte), nil +} + +func (s *controller) GenerateCert(ctx context.Context) ([]byte, []byte, error) { + certData := map[string]interface{}{ + "common_name": s.domainName, + } + cert, err := s.store.Write(ctx, "pki_int/issue/example-dot-com", certData) + if err != nil { + return nil, nil, err + } + return cert["certificate"].([]byte), cert["private_key"].([]byte), nil +} + +func (s *controller) runtime() { + t := time.Tick(time.Hour) + for { + select { + case <-t: + cert, err := s.readCertificate(s.domainName) + if cert == nil || time.Until(cert.Leaf.NotAfter) < s.validInterval { + ctx, cancel := context.WithTimeout(context.Background(), s.storeTimeout) + certData, keyData, err := s.GenerateCert(ctx) + if err != nil { + zap.L().Error("generate certificate", zap.Error(err)) + } + cancel() + if err := s.storeCertificate(s.certPath, certData); err != nil { + zap.L().Error("store certificate", zap.Error(err)) + } + if err := s.storeKey(s.keyPath, keyData); err != nil { + zap.L().Error("store key", zap.Error(err)) + } + } + if err != nil { + zap.L().Error("read certificate", zap.Error(err)) + } + } + } } diff --git a/internal/controller/types.go b/internal/controller/types.go index c488b85..9971410 100644 --- a/internal/controller/types.go +++ b/internal/controller/types.go @@ -1,7 +1,19 @@ package controller +import ( + "time" +) + type Config struct { - CommonName string + CommonName string + DomainName string + VaultIntermediateCAPath string + VaultCertPath string + VaultTimeout time.Duration + + CertPath string + KeyPath string + CaPath string - VaultCAPath string + ValidInterval time.Duration } From c240ed861252c191516f145abd25b437b41eda3e Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 14 Jun 2022 17:42:00 +0300 Subject: [PATCH 003/220] first variant --- README.md | 18 +++++++++- cmd/cert-deamon/main.go | 60 +++++++++++++++++++++++++++++++ go.mod | 1 + go.sum | 1 + internal/config/config.go | 45 ++++++++++++++++++++--- internal/controller/controller.go | 10 +++--- internal/controller/types.go | 11 +++--- internal/utils/utils.go | 34 ++++++++++++++++++ 8 files changed, 163 insertions(+), 17 deletions(-) create mode 100644 cmd/cert-deamon/main.go create mode 100644 internal/utils/utils.go diff --git a/README.md b/README.md index 69ca7b4..2de7f3e 100644 --- a/README.md +++ b/README.md @@ -1 +1,17 @@ -# key-keeper \ No newline at end of file +# key-keeper + +Пример config.yml +```yaml +vault: + address: "address vault" + token: "unexpired token" + intermediate_ca_path: "path for saving intermediate ca" + cert_path: "path for generate certificate" + timeout: "timeout request: 1s, 3m, 5h" +certificate: + common_name: "common_name" + domain_name: "domain_name" + cert_path: "path for save cert on host" + key_path: "path for save key on host" + valid_interval: "valid expire cert interval: 1s, 3m, 5h" +``` diff --git a/cmd/cert-deamon/main.go b/cmd/cert-deamon/main.go new file mode 100644 index 0000000..a1925aa --- /dev/null +++ b/cmd/cert-deamon/main.go @@ -0,0 +1,60 @@ +package main + +import ( + "os" + "os/signal" + "syscall" + + "go.uber.org/zap" + + "github.com/terra-cube/key-keeper/internal/config" + "github.com/terra-cube/key-keeper/internal/controller" + "github.com/terra-cube/key-keeper/internal/vault" +) + +const configPath = "./config.yml" + +func main() { + cfg, err := config.Read(configPath) + if err != nil { + zap.L().Fatal("read configuration", zap.Error(err)) + } + + zap.L().Debug("configuration", zap.Any("config", cfg)) + + v, err := vault.New( + cfg.Vault.Address, + cfg.Vault.Token, + ) + if err != nil { + zap.L().Fatal("init vault", zap.Error(err)) + } + + cntl := controller.New( + v, + controller.Config{ + VaultIntermediateCAPath: cfg.Vault.IntermediateCAPath, + VaultCertPath: cfg.Vault.CertPath, + VaultTimeout: cfg.Vault.Timeout.Duration, + + CommonName: cfg.Certificate.CommonName, + DomainName: cfg.Certificate.DomainName, + CaPath: cfg.Certificate.CaPath, + CertPath: cfg.Certificate.CertPath, + KeyPath: cfg.Certificate.KeyPath, + ValidInterval: cfg.Certificate.ValidInterval.Duration, + }, + ) + + go func() { + if err := cntl.TurnOn(); err != nil { + zap.L().Fatal("start", zap.Error(err)) + } + }() + + zap.L().Info("started") + + ch := make(chan os.Signal, 1) + signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM) + <-ch +} diff --git a/go.mod b/go.mod index 7c71731..223649d 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.18 require ( github.com/hashicorp/vault/api v1.7.1 go.uber.org/zap v1.21.0 + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b ) require ( diff --git a/go.sum b/go.sum index f1270ec..069b4b0 100644 --- a/go.sum +++ b/go.sum @@ -343,6 +343,7 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= diff --git a/internal/config/config.go b/internal/config/config.go index 4ac6fb4..84fa402 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1,10 +1,45 @@ package config +import ( + "fmt" + "io/ioutil" + + "gopkg.in/yaml.v3" + + "github.com/terra-cube/key-keeper/internal/utils" +) + type Configuration struct { - BaseDomain string `yaml:"base_domain"` - Certificates []Certificate `yaml:"certificates"` + Vault vault `yaml:"vault"` + Certificate certificate `yaml:"certificate"` +} + +type vault struct { + Address string `yaml:"address"` + Token string `yaml:"token"` + IntermediateCAPath string `yaml:"intermediate_ca_path"` + CertPath string `yaml:"cert_path"` + Timeout utils.Duration `yaml:"timeout"` +} + +type certificate struct { + CommonName string `yaml:"common_name"` + DomainName string `yaml:"domain_name"` + CaPath string `yaml:"ca_path"` + CertPath string `yaml:"cert_path"` + KeyPath string `yaml:"key_path"` + ValidInterval utils.Duration `yaml:"valid_interval"` } -type Certificate struct{ - -} \ No newline at end of file +func Read(path string) (cfg Configuration, err error) { + data, err := ioutil.ReadFile(path) + if err != nil { + err = fmt.Errorf("read config file %s: %w", path, err) + return + } + if err = yaml.Unmarshal(data, &cfg); err != nil { + err = fmt.Errorf("unmarshal config %w", err) + return + } + return +} diff --git a/internal/controller/controller.go b/internal/controller/controller.go index abd483f..9a4b130 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -20,11 +20,11 @@ type store interface { type controller struct { store store - commonName string - domainName string storeIntermediateCAPath string storeCertPath string storeTimeout time.Duration + commonName string + domainName string certPath string keyPath string caPath string @@ -35,11 +35,11 @@ func New(store store, cfg Config) *controller { c := &controller{ store: store, - commonName: cfg.CommonName, - domainName: cfg.DomainName, storeIntermediateCAPath: cfg.VaultCertPath, storeCertPath: cfg.VaultCertPath, storeTimeout: cfg.VaultTimeout, + commonName: cfg.CommonName, + domainName: cfg.DomainName, certPath: cfg.CertPath, keyPath: cfg.KeyPath, caPath: cfg.CaPath, @@ -129,7 +129,7 @@ func (s *controller) GenerateCert(ctx context.Context) ([]byte, []byte, error) { certData := map[string]interface{}{ "common_name": s.domainName, } - cert, err := s.store.Write(ctx, "pki_int/issue/example-dot-com", certData) + cert, err := s.store.Write(ctx, s.storeCertPath, certData) if err != nil { return nil, nil, err } diff --git a/internal/controller/types.go b/internal/controller/types.go index 9971410..6f47199 100644 --- a/internal/controller/types.go +++ b/internal/controller/types.go @@ -5,15 +5,14 @@ import ( ) type Config struct { - CommonName string - DomainName string VaultIntermediateCAPath string VaultCertPath string VaultTimeout time.Duration - CertPath string - KeyPath string - CaPath string - + CommonName string + DomainName string + CertPath string + KeyPath string + CaPath string ValidInterval time.Duration } diff --git a/internal/utils/utils.go b/internal/utils/utils.go new file mode 100644 index 0000000..d74de9e --- /dev/null +++ b/internal/utils/utils.go @@ -0,0 +1,34 @@ +package utils + +import ( + "encoding/json" + "fmt" + "time" +) + +type Duration struct { + time.Duration +} + +func (duration *Duration) UnmarshalYAML(b []byte) error { + var unmarshalledJson interface{} + + err := json.Unmarshal(b, &unmarshalledJson) + if err != nil { + return err + } + + switch value := unmarshalledJson.(type) { + case float64: + duration.Duration = time.Duration(value) + case string: + duration.Duration, err = time.ParseDuration(value) + if err != nil { + return err + } + default: + return fmt.Errorf("invalid duration: %#v", unmarshalledJson) + } + + return nil +} From 6b134e5132d40958ed61642febebde9dc366576a Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 14 Jun 2022 18:11:51 +0300 Subject: [PATCH 004/220] update readme --- README.md | 30 ++++++++++++++++--------- cmd/{cert-deamon => key-keeper}/main.go | 19 ++++++++++++++-- 2 files changed, 36 insertions(+), 13 deletions(-) rename cmd/{cert-deamon => key-keeper}/main.go (77%) diff --git a/README.md b/README.md index 2de7f3e..b2464e1 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,25 @@ # key-keeper -Пример config.yml +Example config.yml + ```yaml vault: - address: "address vault" - token: "unexpired token" - intermediate_ca_path: "path for saving intermediate ca" - cert_path: "path for generate certificate" - timeout: "timeout request: 1s, 3m, 5h" + address: "address vault" + token: "unexpired token" + intermediate_ca_path: "path for saving intermediate ca" + cert_path: "path for generate certificate" + timeout: "timeout request: 1s, 3m, 5h" certificate: - common_name: "common_name" - domain_name: "domain_name" - cert_path: "path for save cert on host" - key_path: "path for save key on host" - valid_interval: "valid expire cert interval: 1s, 3m, 5h" + common_name: "common_name" + domain_name: "domain_name" + cert_path: "path for save cert on host" + key_path: "path for save key on host" + valid_interval: "valid expire cert interval: 1s, 3m, 5h" ``` + +Build: + + go build -o cmd/key-keeper/main.go -o key-keeper +Run: + + key-keeper -config /path/to/config \ No newline at end of file diff --git a/cmd/cert-deamon/main.go b/cmd/key-keeper/main.go similarity index 77% rename from cmd/cert-deamon/main.go rename to cmd/key-keeper/main.go index a1925aa..07ca8ed 100644 --- a/cmd/cert-deamon/main.go +++ b/cmd/key-keeper/main.go @@ -1,6 +1,7 @@ package main import ( + "flag" "os" "os/signal" "syscall" @@ -12,9 +13,23 @@ import ( "github.com/terra-cube/key-keeper/internal/vault" ) -const configPath = "./config.yml" - func main() { + loggerConfig := zap.NewProductionConfig() + loggerConfig.Level.SetLevel(zap.DebugLevel) + logger, err := loggerConfig.Build() + if err != nil { + panic(err) + } + zap.ReplaceGlobals(logger) + + var configPath string + flag.StringVar(&configPath, "config", "", "path to config file") + flag.Parse() + + if configPath == "" { + zap.L().Fatal("not found config param") + } + cfg, err := config.Read(configPath) if err != nil { zap.L().Fatal("read configuration", zap.Error(err)) From 729da556bbdfd9eb256a45aa76b747fee901d957 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 14 Jun 2022 19:10:30 +0300 Subject: [PATCH 005/220] up --- .gitignore | 3 ++- README.md | 2 +- cmd/key-keeper/main.go | 4 ++-- internal/config/config.go | 25 ++++++++++++------------- internal/utils/utils.go | 34 ---------------------------------- 5 files changed, 17 insertions(+), 51 deletions(-) delete mode 100644 internal/utils/utils.go diff --git a/.gitignore b/.gitignore index b59f7e3..4f50485 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -test/ \ No newline at end of file +test/ +key-keeper \ No newline at end of file diff --git a/README.md b/README.md index b2464e1..1399bd3 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ certificate: Build: - go build -o cmd/key-keeper/main.go -o key-keeper + go build -o key-keeper cmd/key-keeper/main.go Run: key-keeper -config /path/to/config \ No newline at end of file diff --git a/cmd/key-keeper/main.go b/cmd/key-keeper/main.go index 07ca8ed..7b71e29 100644 --- a/cmd/key-keeper/main.go +++ b/cmd/key-keeper/main.go @@ -50,14 +50,14 @@ func main() { controller.Config{ VaultIntermediateCAPath: cfg.Vault.IntermediateCAPath, VaultCertPath: cfg.Vault.CertPath, - VaultTimeout: cfg.Vault.Timeout.Duration, + VaultTimeout: cfg.Vault.Timeout, CommonName: cfg.Certificate.CommonName, DomainName: cfg.Certificate.DomainName, CaPath: cfg.Certificate.CaPath, CertPath: cfg.Certificate.CertPath, KeyPath: cfg.Certificate.KeyPath, - ValidInterval: cfg.Certificate.ValidInterval.Duration, + ValidInterval: cfg.Certificate.ValidInterval, }, ) diff --git a/internal/config/config.go b/internal/config/config.go index 84fa402..4853a3f 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -3,10 +3,9 @@ package config import ( "fmt" "io/ioutil" + "time" "gopkg.in/yaml.v3" - - "github.com/terra-cube/key-keeper/internal/utils" ) type Configuration struct { @@ -15,20 +14,20 @@ type Configuration struct { } type vault struct { - Address string `yaml:"address"` - Token string `yaml:"token"` - IntermediateCAPath string `yaml:"intermediate_ca_path"` - CertPath string `yaml:"cert_path"` - Timeout utils.Duration `yaml:"timeout"` + Address string `yaml:"address"` + Token string `yaml:"token"` + IntermediateCAPath string `yaml:"intermediate_ca_path"` + CertPath string `yaml:"cert_path"` + Timeout time.Duration `yaml:"timeout"` } type certificate struct { - CommonName string `yaml:"common_name"` - DomainName string `yaml:"domain_name"` - CaPath string `yaml:"ca_path"` - CertPath string `yaml:"cert_path"` - KeyPath string `yaml:"key_path"` - ValidInterval utils.Duration `yaml:"valid_interval"` + CommonName string `yaml:"common_name"` + DomainName string `yaml:"domain_name"` + CaPath string `yaml:"ca_path"` + CertPath string `yaml:"cert_path"` + KeyPath string `yaml:"key_path"` + ValidInterval time.Duration `yaml:"valid_interval"` } func Read(path string) (cfg Configuration, err error) { diff --git a/internal/utils/utils.go b/internal/utils/utils.go deleted file mode 100644 index d74de9e..0000000 --- a/internal/utils/utils.go +++ /dev/null @@ -1,34 +0,0 @@ -package utils - -import ( - "encoding/json" - "fmt" - "time" -) - -type Duration struct { - time.Duration -} - -func (duration *Duration) UnmarshalYAML(b []byte) error { - var unmarshalledJson interface{} - - err := json.Unmarshal(b, &unmarshalledJson) - if err != nil { - return err - } - - switch value := unmarshalledJson.(type) { - case float64: - duration.Duration = time.Duration(value) - case string: - duration.Duration, err = time.ParseDuration(value) - if err != nil { - return err - } - default: - return fmt.Errorf("invalid duration: %#v", unmarshalledJson) - } - - return nil -} From a9022699da792035b7c4e9abaa00e0f055b78b38 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 14 Jun 2022 20:08:49 +0300 Subject: [PATCH 006/220] up intermediate ca generation --- README.md | 16 +-- cmd/key-keeper/main.go | 13 +- internal/config/config.go | 27 +--- internal/controller/certificate.go | 46 +++---- internal/controller/controller.go | 214 +++++++++++++++-------------- internal/controller/types.go | 26 ++-- 6 files changed, 161 insertions(+), 181 deletions(-) diff --git a/README.md b/README.md index 1399bd3..773dca6 100644 --- a/README.md +++ b/README.md @@ -6,20 +6,20 @@ Example config.yml vault: address: "address vault" token: "unexpired token" - intermediate_ca_path: "path for saving intermediate ca" - cert_path: "path for generate certificate" timeout: "timeout request: 1s, 3m, 5h" -certificate: - common_name: "common_name" - domain_name: "domain_name" - cert_path: "path for save cert on host" - key_path: "path for save key on host" +certificates: + root_path: "root ca path" + cert_path: "path for generate certificate" valid_interval: "valid expire cert interval: 1s, 3m, 5h" + ca: + store_path: "path for store of ca" + common_name: "common_name" ``` Build: go build -o key-keeper cmd/key-keeper/main.go + Run: - key-keeper -config /path/to/config \ No newline at end of file + key-keeper -config /path/to/config diff --git a/cmd/key-keeper/main.go b/cmd/key-keeper/main.go index 7b71e29..6666409 100644 --- a/cmd/key-keeper/main.go +++ b/cmd/key-keeper/main.go @@ -47,18 +47,7 @@ func main() { cntl := controller.New( v, - controller.Config{ - VaultIntermediateCAPath: cfg.Vault.IntermediateCAPath, - VaultCertPath: cfg.Vault.CertPath, - VaultTimeout: cfg.Vault.Timeout, - - CommonName: cfg.Certificate.CommonName, - DomainName: cfg.Certificate.DomainName, - CaPath: cfg.Certificate.CaPath, - CertPath: cfg.Certificate.CertPath, - KeyPath: cfg.Certificate.KeyPath, - ValidInterval: cfg.Certificate.ValidInterval, - }, + cfg, ) go func() { diff --git a/internal/config/config.go b/internal/config/config.go index 4853a3f..faa9c6d 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -3,34 +3,13 @@ package config import ( "fmt" "io/ioutil" - "time" "gopkg.in/yaml.v3" -) - -type Configuration struct { - Vault vault `yaml:"vault"` - Certificate certificate `yaml:"certificate"` -} -type vault struct { - Address string `yaml:"address"` - Token string `yaml:"token"` - IntermediateCAPath string `yaml:"intermediate_ca_path"` - CertPath string `yaml:"cert_path"` - Timeout time.Duration `yaml:"timeout"` -} - -type certificate struct { - CommonName string `yaml:"common_name"` - DomainName string `yaml:"domain_name"` - CaPath string `yaml:"ca_path"` - CertPath string `yaml:"cert_path"` - KeyPath string `yaml:"key_path"` - ValidInterval time.Duration `yaml:"valid_interval"` -} + "github.com/terra-cube/key-keeper/internal/controller" +) -func Read(path string) (cfg Configuration, err error) { +func Read(path string) (cfg controller.Config, err error) { data, err := ioutil.ReadFile(path) if err != nil { err = fmt.Errorf("read config file %s: %w", path, err) diff --git a/internal/controller/certificate.go b/internal/controller/certificate.go index a6beb63..5915483 100644 --- a/internal/controller/certificate.go +++ b/internal/controller/certificate.go @@ -1,8 +1,6 @@ package controller import ( - "crypto/tls" - "crypto/x509" "fmt" "os" ) @@ -21,28 +19,28 @@ func (s *controller) storeKey(path string, key []byte) error { return nil } -func (s *controller) readCertificate(domain string) (*tls.Certificate, error) { - crtContent, err := os.ReadFile(s.certPath) - if err != nil { - return nil, err - } +// func (s *controller) readCertificate(domain string) (*tls.Certificate, error) { +// crtContent, err := os.ReadFile(s.certPath) +// if err != nil { +// return nil, err +// } - keyContent, err := os.ReadFile(s.keyPath) - if err != nil { - return nil, err - } +// keyContent, err := os.ReadFile(s.keyPath) +// if err != nil { +// return nil, err +// } - cert, err := tls.X509KeyPair(crtContent, keyContent) - if err != nil { - return nil, fmt.Errorf("failed to parse x509 key pair: %w", err) - } - if len(cert.Certificate) == 0 { - return nil, fmt.Errorf("list of certificates is empty") - } +// cert, err := tls.X509KeyPair(crtContent, keyContent) +// if err != nil { +// return nil, fmt.Errorf("failed to parse x509 key pair: %w", err) +// } +// if len(cert.Certificate) == 0 { +// return nil, fmt.Errorf("list of certificates is empty") +// } - cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0]) - if err != nil { - return nil, err - } - return &cert, nil -} +// cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0]) +// if err != nil { +// return nil, err +// } +// return &cert, nil +// } diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 9a4b130..00b5cc7 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -3,162 +3,168 @@ package controller import ( "context" "fmt" - "os" "time" - - "go.uber.org/zap" ) var intermediateCommonNameLayout = "%s Intermediate Authority" -type store interface { +type vault interface { Write(ctx context.Context, path string, data map[string]interface{}) (map[string]interface{}, error) Read(ctx context.Context, path string) (map[string]interface{}, error) List(ctx context.Context, path string) (map[string]interface{}, error) } type controller struct { - store store - - storeIntermediateCAPath string - storeCertPath string - storeTimeout time.Duration - commonName string - domainName string - certPath string - keyPath string - caPath string - validInterval time.Duration + vault vault + + vaultTimeout time.Duration + + certs Certificates } -func New(store store, cfg Config) *controller { +func New(store vault, cfg Config) *controller { c := &controller{ - store: store, - - storeIntermediateCAPath: cfg.VaultCertPath, - storeCertPath: cfg.VaultCertPath, - storeTimeout: cfg.VaultTimeout, - commonName: cfg.CommonName, - domainName: cfg.DomainName, - certPath: cfg.CertPath, - keyPath: cfg.KeyPath, - caPath: cfg.CaPath, - validInterval: cfg.ValidInterval, + vault: store, + + vaultTimeout: cfg.Vault.Timeout, + certs: cfg.Certs, } return c } func (s *controller) TurnOn() error { - cert, err := s.readCertificate(s.domainName) - if cert != nil && time.Until(cert.Leaf.NotAfter) > s.validInterval { - return nil - } - if err != nil && !os.IsNotExist(err) { - return err - } - - ctx, cancel := context.WithTimeout(context.Background(), s.storeTimeout) - defer cancel() - - intermediateCA, err := s.GenerateIntermediateCA(ctx) + // cert, err := s.readCertificate(s.domainName) + // if cert != nil && time.Until(cert.Leaf.NotAfter) > s.validInterval { + // return nil + // } + // if err != nil && !os.IsNotExist(err) { + // return err + // } + + //create intermediate CA with common name example.com + icaCert, icaKey, err := s.GenerateIntermediateCA() if err != nil { return err } - if err := s.storeCertificate(s.caPath, intermediateCA); err != nil { - return err - } - ctx, cancel = context.WithTimeout(context.Background(), s.storeTimeout) - defer cancel() - - certData, keyData, err := s.GenerateCert(ctx) - if err != nil { + if err := s.storeCertificate("/etc/kubernetes/pki/ca/root-ca.pem", icaCert); err != nil { return err } - if err := s.storeCertificate(s.certPath, certData); err != nil { - return err - } - if err := s.storeKey(s.keyPath, keyData); err != nil { + + if err := s.storeKey("/etc/kubernetes/pki/ca/root-ca-key.pem", icaKey); err != nil { return err } - go s.runtime() + // ctx, cancel = context.WithTimeout(context.Background(), s.vaultTimeout) + // defer cancel() + // certData, keyData, err := s.GenerateCert(ctx) + // if err != nil { + // return err + // } + // if err := s.storeCertificate(s.certPath, certData); err != nil { + // return err + // } + // if err := s.storeKey(s.keyPath, keyData); err != nil { + // return err + // } + + // go s.runtime() return nil } -func (s *controller) GenerateIntermediateCA(ctx context.Context) ([]byte, error) { - cert, _ := s.store.Read(ctx, s.storeIntermediateCAPath) +func (s *controller) GenerateIntermediateCA() (cert []byte, key []byte, err error) { + ctx, cancel := context.WithTimeout(context.Background(), s.vaultTimeout) + defer cancel() + storedICA, _ := s.vault.Read(ctx, s.certs.CA.StorePath) if cert != nil { - return cert["certificate"].([]byte), nil + return storedICA["certificate"].([]byte), storedICA["private_key"].([]byte), nil } - //TODO: check expire + + // create intermediate CA + ctx, cancel = context.WithTimeout(context.Background(), s.vaultTimeout) + defer cancel() + csrData := map[string]interface{}{ - "common_name": fmt.Sprintf(intermediateCommonNameLayout, s.commonName), + "common_name": fmt.Sprintf(intermediateCommonNameLayout, s.certs.CA.CommonName), "ttl": "8760h", } - csr, err := s.store.Write(ctx, "pki_int/intermediate/generate/internal", csrData) + + csr, err := s.vault.Write(ctx, s.certs.CertPath+"/intermediate/generate/internal", csrData) if err != nil { - return nil, err + return } - pemData := map[string]interface{}{ + // send the intermediate CA's CSR to the root CA for signing + ctx, cancel = context.WithTimeout(context.Background(), s.vaultTimeout) + defer cancel() + + icaData := map[string]interface{}{ "csr": csr["csr"], "format": "pem_bundle", "ttl": "8760h", } - pem, err := s.store.Write(ctx, "pki/root/sign-intermediate", pemData) + + ica, err := s.vault.Write(ctx, s.certs.RootPath+"/root/sign-intermediate", icaData) if err != nil { - return nil, err + return } + // publish the signed certificate back to the Intermediate CA + ctx, cancel = context.WithTimeout(context.Background(), s.vaultTimeout) + defer cancel() + certData := map[string]interface{}{ - "certificate": pem["certificate"], - } - if _, err = s.store.Write(ctx, "pki_int/intermediate/set-signed", certData); err != nil { - return nil, err + "certificate": ica["certificate"], } - if _, err = s.store.Write(ctx, s.storeIntermediateCAPath, pem); err != nil { - return nil, err + if _, err = s.vault.Write(ctx, s.certs.CertPath+"/intermediate/set-signed", certData); err != nil { + return } - return pem["certificate"].([]byte), nil -} -func (s *controller) GenerateCert(ctx context.Context) ([]byte, []byte, error) { - certData := map[string]interface{}{ - "common_name": s.domainName, - } - cert, err := s.store.Write(ctx, s.storeCertPath, certData) - if err != nil { - return nil, nil, err - } - return cert["certificate"].([]byte), cert["private_key"].([]byte), nil -} + ctx, cancel = context.WithTimeout(context.Background(), s.vaultTimeout) + defer cancel() -func (s *controller) runtime() { - t := time.Tick(time.Hour) - for { - select { - case <-t: - cert, err := s.readCertificate(s.domainName) - if cert == nil || time.Until(cert.Leaf.NotAfter) < s.validInterval { - ctx, cancel := context.WithTimeout(context.Background(), s.storeTimeout) - certData, keyData, err := s.GenerateCert(ctx) - if err != nil { - zap.L().Error("generate certificate", zap.Error(err)) - } - cancel() - if err := s.storeCertificate(s.certPath, certData); err != nil { - zap.L().Error("store certificate", zap.Error(err)) - } - if err := s.storeKey(s.keyPath, keyData); err != nil { - zap.L().Error("store key", zap.Error(err)) - } - } - if err != nil { - zap.L().Error("read certificate", zap.Error(err)) - } - } + if _, err = s.vault.Write(ctx, s.certs.CA.StorePath, ica); err != nil { + return } + return ica["certificate"].([]byte), ica["private_key"].([]byte), nil } + +// func (s *controller) GenerateCert(ctx context.Context) ([]byte, []byte, error) { +// certData := map[string]interface{}{ +// "common_name": s.domainName, +// } +// cert, err := s.vault.Write(ctx, s.vaultCertPath, certData) +// if err != nil { +// return nil, nil, err +// } +// return cert["certificate"].([]byte), cert["private_key"].([]byte), nil +// } + +// func (s *controller) runtime() { +// t := time.Tick(time.Hour) +// for { +// select { +// case <-t: +// cert, err := s.readCertificate(s.domainName) +// if cert == nil || time.Until(cert.Leaf.NotAfter) < s.validInterval { +// ctx, cancel := context.WithTimeout(context.Background(), s.vaultTimeout) +// certData, keyData, err := s.GenerateCert(ctx) +// if err != nil { +// zap.L().Error("generate certificate", zap.Error(err)) +// } +// cancel() +// if err := s.storeCertificate(s.certPath, certData); err != nil { +// zap.L().Error("store certificate", zap.Error(err)) +// } +// if err := s.storeKey(s.keyPath, keyData); err != nil { +// zap.L().Error("store key", zap.Error(err)) +// } +// } +// if err != nil { +// zap.L().Error("read certificate", zap.Error(err)) +// } +// } +// } +// } diff --git a/internal/controller/types.go b/internal/controller/types.go index 6f47199..d31c4c8 100644 --- a/internal/controller/types.go +++ b/internal/controller/types.go @@ -5,14 +5,22 @@ import ( ) type Config struct { - VaultIntermediateCAPath string - VaultCertPath string - VaultTimeout time.Duration + Vault Vault `yaml:"vault"` + Certs Certificates `yaml:"certificates"` +} + +type Vault struct { + Address string `yaml:"address"` + Token string `yaml:"token"` + Timeout time.Duration `yaml:"timeout"` +} - CommonName string - DomainName string - CertPath string - KeyPath string - CaPath string - ValidInterval time.Duration +type Certificates struct { + RootPath string `yaml:"root_path"` + CertPath string `yaml:"cert_path"` + ValidInterval time.Duration `yaml:"valid_interval"` + CA struct { + StorePath string `yaml:"store_path"` + CommonName string `yaml:"common_name"` + } `yaml:"ca"` } From a3e93df5bd49f6f85dfb9225e4267cac5eb7255a Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 14 Jun 2022 20:22:19 +0300 Subject: [PATCH 007/220] update --- README.md | 3 ++- internal/controller/controller.go | 8 ++++---- internal/controller/types.go | 3 ++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 773dca6..6b3dcf3 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,9 @@ certificates: cert_path: "path for generate certificate" valid_interval: "valid expire cert interval: 1s, 3m, 5h" ca: - store_path: "path for store of ca" common_name: "common_name" + vault_path: "path for store of ca in vault" + path: "path for store of ca in host" ``` Build: diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 00b5cc7..a72bbe3 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -47,11 +47,11 @@ func (s *controller) TurnOn() error { return err } - if err := s.storeCertificate("/etc/kubernetes/pki/ca/root-ca.pem", icaCert); err != nil { + if err := s.storeCertificate(s.certs.CA.Path+".pem", icaCert); err != nil { return err } - if err := s.storeKey("/etc/kubernetes/pki/ca/root-ca-key.pem", icaKey); err != nil { + if err := s.storeKey(s.certs.CA.Path+"-key.pem", icaKey); err != nil { return err } @@ -75,7 +75,7 @@ func (s *controller) TurnOn() error { func (s *controller) GenerateIntermediateCA() (cert []byte, key []byte, err error) { ctx, cancel := context.WithTimeout(context.Background(), s.vaultTimeout) defer cancel() - storedICA, _ := s.vault.Read(ctx, s.certs.CA.StorePath) + storedICA, _ := s.vault.Read(ctx, s.certs.CA.VaultPath) if cert != nil { return storedICA["certificate"].([]byte), storedICA["private_key"].([]byte), nil } @@ -125,7 +125,7 @@ func (s *controller) GenerateIntermediateCA() (cert []byte, key []byte, err erro ctx, cancel = context.WithTimeout(context.Background(), s.vaultTimeout) defer cancel() - if _, err = s.vault.Write(ctx, s.certs.CA.StorePath, ica); err != nil { + if _, err = s.vault.Write(ctx, s.certs.CA.VaultPath, ica); err != nil { return } return ica["certificate"].([]byte), ica["private_key"].([]byte), nil diff --git a/internal/controller/types.go b/internal/controller/types.go index d31c4c8..33a3cd0 100644 --- a/internal/controller/types.go +++ b/internal/controller/types.go @@ -20,7 +20,8 @@ type Certificates struct { CertPath string `yaml:"cert_path"` ValidInterval time.Duration `yaml:"valid_interval"` CA struct { - StorePath string `yaml:"store_path"` CommonName string `yaml:"common_name"` + VaultPath string `yaml:"vault_path"` + Path string `yaml:"path"` } `yaml:"ca"` } From ad04b10fc1eecbb07f4213f959c8c4da83d230a8 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 14 Jun 2022 21:21:07 +0300 Subject: [PATCH 008/220] up --- internal/controller/certificate.go | 4 ++-- internal/controller/controller.go | 14 +++++++++----- internal/controller/types.go | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/internal/controller/certificate.go b/internal/controller/certificate.go index 5915483..80e7110 100644 --- a/internal/controller/certificate.go +++ b/internal/controller/certificate.go @@ -6,14 +6,14 @@ import ( ) func (s *controller) storeCertificate(path string, cert []byte) error { - if err := os.WriteFile(path, cert, 0644); err != nil { + if err := os.WriteFile(path+".pem", cert, 0644); err != nil { return fmt.Errorf("failed to save certificate with path %s: %w", path, err) } return nil } func (s *controller) storeKey(path string, key []byte) error { - if err := os.WriteFile(path, key, 0600); err != nil { + if err := os.WriteFile(path+"-key.pem", key, 0600); err != nil { return fmt.Errorf("failed to save key file: %w", err) } return nil diff --git a/internal/controller/controller.go b/internal/controller/controller.go index a72bbe3..e43091a 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -47,11 +47,11 @@ func (s *controller) TurnOn() error { return err } - if err := s.storeCertificate(s.certs.CA.Path+".pem", icaCert); err != nil { + if err := s.storeCertificate(s.certs.CA.HostPath, icaCert); err != nil { return err } - if err := s.storeKey(s.certs.CA.Path+"-key.pem", icaKey); err != nil { + if err := s.storeKey(s.certs.CA.HostPath, icaKey); err != nil { return err } @@ -90,7 +90,7 @@ func (s *controller) GenerateIntermediateCA() (cert []byte, key []byte, err erro "ttl": "8760h", } - csr, err := s.vault.Write(ctx, s.certs.CertPath+"/intermediate/generate/internal", csrData) + csr, err := s.vault.Write(ctx, s.certs.CertPath+"/intermediate/generate/exported", csrData) if err != nil { return } @@ -125,10 +125,14 @@ func (s *controller) GenerateIntermediateCA() (cert []byte, key []byte, err erro ctx, cancel = context.WithTimeout(context.Background(), s.vaultTimeout) defer cancel() - if _, err = s.vault.Write(ctx, s.certs.CA.VaultPath, ica); err != nil { + storedICA = map[string]interface{}{ + "certificate": ica["certificate"], + "private_key": csr["private_key"], + } + if _, err = s.vault.Write(ctx, s.certs.CA.VaultPath, storedICA); err != nil { return } - return ica["certificate"].([]byte), ica["private_key"].([]byte), nil + return ica["certificate"].([]byte), csr["private_key"].([]byte), nil } // func (s *controller) GenerateCert(ctx context.Context) ([]byte, []byte, error) { diff --git a/internal/controller/types.go b/internal/controller/types.go index 33a3cd0..10681b6 100644 --- a/internal/controller/types.go +++ b/internal/controller/types.go @@ -22,6 +22,6 @@ type Certificates struct { CA struct { CommonName string `yaml:"common_name"` VaultPath string `yaml:"vault_path"` - Path string `yaml:"path"` + HostPath string `yaml:"host_path"` } `yaml:"ca"` } From 9c98d1885496a676a693face2e9e125d5033f6bb Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 14 Jun 2022 21:46:51 +0300 Subject: [PATCH 009/220] up --- README.md | 4 ++-- internal/controller/controller.go | 6 ++++-- internal/controller/types.go | 2 +- internal/vault/vault.go | 13 +++++++++++++ 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 6b3dcf3..0eb16bf 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,8 @@ certificates: valid_interval: "valid expire cert interval: 1s, 3m, 5h" ca: common_name: "common_name" - vault_path: "path for store of ca in vault" - path: "path for store of ca in host" + vault_kv: "path for store of ca in vault" + host_path: "path for store of ca in host" ``` Build: diff --git a/internal/controller/controller.go b/internal/controller/controller.go index e43091a..0262c32 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -12,6 +12,8 @@ type vault interface { Write(ctx context.Context, path string, data map[string]interface{}) (map[string]interface{}, error) Read(ctx context.Context, path string) (map[string]interface{}, error) List(ctx context.Context, path string) (map[string]interface{}, error) + Put(ctx context.Context, mountPath, secretePath string, data map[string]interface{}) error + Get(ctx context.Context, mountPath, secretePath string) (map[string]interface{}, error) } type controller struct { @@ -75,7 +77,7 @@ func (s *controller) TurnOn() error { func (s *controller) GenerateIntermediateCA() (cert []byte, key []byte, err error) { ctx, cancel := context.WithTimeout(context.Background(), s.vaultTimeout) defer cancel() - storedICA, _ := s.vault.Read(ctx, s.certs.CA.VaultPath) + storedICA, _ := s.vault.Get(ctx, s.certs.CA.VaultKV, "intermediate-ca") if cert != nil { return storedICA["certificate"].([]byte), storedICA["private_key"].([]byte), nil } @@ -129,7 +131,7 @@ func (s *controller) GenerateIntermediateCA() (cert []byte, key []byte, err erro "certificate": ica["certificate"], "private_key": csr["private_key"], } - if _, err = s.vault.Write(ctx, s.certs.CA.VaultPath, storedICA); err != nil { + if err = s.vault.Put(ctx, s.certs.CA.VaultKV, "intermediate-ca", storedICA); err != nil { return } return ica["certificate"].([]byte), csr["private_key"].([]byte), nil diff --git a/internal/controller/types.go b/internal/controller/types.go index 10681b6..c987162 100644 --- a/internal/controller/types.go +++ b/internal/controller/types.go @@ -21,7 +21,7 @@ type Certificates struct { ValidInterval time.Duration `yaml:"valid_interval"` CA struct { CommonName string `yaml:"common_name"` - VaultPath string `yaml:"vault_path"` + VaultKV string `yaml:"vault_kv"` HostPath string `yaml:"host_path"` } `yaml:"ca"` } diff --git a/internal/vault/vault.go b/internal/vault/vault.go index f185c05..83f84f0 100644 --- a/internal/vault/vault.go +++ b/internal/vault/vault.go @@ -53,3 +53,16 @@ func (c *vault) Write(ctx context.Context, path string, data map[string]interfac } return nil, err } + +func (c *vault) Put(ctx context.Context, mountPath, secretePath string, data map[string]interface{}) error { + _, err := c.cli.KVv2(mountPath).Put(ctx, secretePath, data) + return err +} + +func (c *vault) Get(ctx context.Context, mountPath, secretePath string) (map[string]interface{}, error) { + s, err := c.cli.KVv2(mountPath).Get(ctx, secretePath) + if s != nil { + return s.Data, err + } + return s.Data, err +} From 3996ec23bd2f4ddf0ced91cca4155afcedfe5de2 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 14 Jun 2022 22:45:14 +0300 Subject: [PATCH 010/220] up --- internal/controller/certificate.go | 46 ++++++++++++++++-------------- internal/vault/vault.go | 2 +- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/internal/controller/certificate.go b/internal/controller/certificate.go index 80e7110..06887af 100644 --- a/internal/controller/certificate.go +++ b/internal/controller/certificate.go @@ -1,6 +1,8 @@ package controller import ( + "crypto/tls" + "crypto/x509" "fmt" "os" ) @@ -19,28 +21,28 @@ func (s *controller) storeKey(path string, key []byte) error { return nil } -// func (s *controller) readCertificate(domain string) (*tls.Certificate, error) { -// crtContent, err := os.ReadFile(s.certPath) -// if err != nil { -// return nil, err -// } +func (s *controller) readCertificate(path string) (*tls.Certificate, error) { + crtContent, err := os.ReadFile(path + ".pem") + if err != nil { + return nil, err + } -// keyContent, err := os.ReadFile(s.keyPath) -// if err != nil { -// return nil, err -// } + keyContent, err := os.ReadFile(path + "-key.pem") + if err != nil { + return nil, err + } -// cert, err := tls.X509KeyPair(crtContent, keyContent) -// if err != nil { -// return nil, fmt.Errorf("failed to parse x509 key pair: %w", err) -// } -// if len(cert.Certificate) == 0 { -// return nil, fmt.Errorf("list of certificates is empty") -// } + cert, err := tls.X509KeyPair(crtContent, keyContent) + if err != nil { + return nil, fmt.Errorf("failed to parse x509 key pair: %w", err) + } + if len(cert.Certificate) == 0 { + return nil, fmt.Errorf("list of certificates is empty") + } -// cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0]) -// if err != nil { -// return nil, err -// } -// return &cert, nil -// } + cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0]) + if err != nil { + return nil, err + } + return &cert, nil +} diff --git a/internal/vault/vault.go b/internal/vault/vault.go index 83f84f0..d4b1596 100644 --- a/internal/vault/vault.go +++ b/internal/vault/vault.go @@ -64,5 +64,5 @@ func (c *vault) Get(ctx context.Context, mountPath, secretePath string) (map[str if s != nil { return s.Data, err } - return s.Data, err + return nil, err } From 47898fa3cdf7d74aca7278076e0861e8dbee6383 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 14 Jun 2022 22:55:58 +0300 Subject: [PATCH 011/220] update --- README.md | 2 +- internal/controller/controller.go | 2 +- internal/controller/types.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0eb16bf..2bdff54 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,10 @@ vault: certificates: root_path: "root ca path" cert_path: "path for generate certificate" + vault_kv: "path for kv" valid_interval: "valid expire cert interval: 1s, 3m, 5h" ca: common_name: "common_name" - vault_kv: "path for store of ca in vault" host_path: "path for store of ca in host" ``` diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 0262c32..b84fe94 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -131,7 +131,7 @@ func (s *controller) GenerateIntermediateCA() (cert []byte, key []byte, err erro "certificate": ica["certificate"], "private_key": csr["private_key"], } - if err = s.vault.Put(ctx, s.certs.CA.VaultKV, "intermediate-ca", storedICA); err != nil { + if err = s.vault.Put(ctx, s.certs.VaultKV, "intermediate-ca", storedICA); err != nil { return } return ica["certificate"].([]byte), csr["private_key"].([]byte), nil diff --git a/internal/controller/types.go b/internal/controller/types.go index c987162..8112f33 100644 --- a/internal/controller/types.go +++ b/internal/controller/types.go @@ -19,9 +19,9 @@ type Certificates struct { RootPath string `yaml:"root_path"` CertPath string `yaml:"cert_path"` ValidInterval time.Duration `yaml:"valid_interval"` + VaultKV string `yaml:"vault_kv"` CA struct { CommonName string `yaml:"common_name"` - VaultKV string `yaml:"vault_kv"` HostPath string `yaml:"host_path"` } `yaml:"ca"` } From 59bb1d353450c797159dc16e4001d5e3340afec1 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 14 Jun 2022 22:57:22 +0300 Subject: [PATCH 012/220] update --- internal/controller/controller.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/controller/controller.go b/internal/controller/controller.go index b84fe94..ce8ac00 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -77,7 +77,7 @@ func (s *controller) TurnOn() error { func (s *controller) GenerateIntermediateCA() (cert []byte, key []byte, err error) { ctx, cancel := context.WithTimeout(context.Background(), s.vaultTimeout) defer cancel() - storedICA, _ := s.vault.Get(ctx, s.certs.CA.VaultKV, "intermediate-ca") + storedICA, _ := s.vault.Get(ctx, s.certs.VaultKV, "intermediate-ca") if cert != nil { return storedICA["certificate"].([]byte), storedICA["private_key"].([]byte), nil } From 66856071a269a242fb16fbffd0f35cc31e20cc0b Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 14 Jun 2022 23:03:16 +0300 Subject: [PATCH 013/220] up: --- internal/controller/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/controller/types.go b/internal/controller/types.go index 8112f33..35706c8 100644 --- a/internal/controller/types.go +++ b/internal/controller/types.go @@ -18,8 +18,8 @@ type Vault struct { type Certificates struct { RootPath string `yaml:"root_path"` CertPath string `yaml:"cert_path"` - ValidInterval time.Duration `yaml:"valid_interval"` VaultKV string `yaml:"vault_kv"` + ValidInterval time.Duration `yaml:"valid_interval"` CA struct { CommonName string `yaml:"common_name"` HostPath string `yaml:"host_path"` From 6f9fddbc67bca36c03a3d1ee1c6c466e0eb5a067 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 14 Jun 2022 23:07:12 +0300 Subject: [PATCH 014/220] up format: --- internal/controller/controller.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/controller/controller.go b/internal/controller/controller.go index ce8ac00..1ac1634 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -79,7 +79,7 @@ func (s *controller) GenerateIntermediateCA() (cert []byte, key []byte, err erro defer cancel() storedICA, _ := s.vault.Get(ctx, s.certs.VaultKV, "intermediate-ca") if cert != nil { - return storedICA["certificate"].([]byte), storedICA["private_key"].([]byte), nil + return []byte(storedICA["certificate"].(string)), []byte(storedICA["private_key"].(string)), nil } //TODO: check expire @@ -134,7 +134,7 @@ func (s *controller) GenerateIntermediateCA() (cert []byte, key []byte, err erro if err = s.vault.Put(ctx, s.certs.VaultKV, "intermediate-ca", storedICA); err != nil { return } - return ica["certificate"].([]byte), csr["private_key"].([]byte), nil + return []byte(ica["certificate"].(string)), []byte(csr["private_key"].(string)), nil } // func (s *controller) GenerateCert(ctx context.Context) ([]byte, []byte, error) { From fa5b056a1c69b10090391dc056e934bd533b2d16 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 14 Jun 2022 23:33:31 +0300 Subject: [PATCH 015/220] up --- internal/controller/controller.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 1ac1634..9cd9a0b 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -4,6 +4,8 @@ import ( "context" "fmt" "time" + + "go.uber.org/zap" ) var intermediateCommonNameLayout = "%s Intermediate Authority" @@ -77,7 +79,10 @@ func (s *controller) TurnOn() error { func (s *controller) GenerateIntermediateCA() (cert []byte, key []byte, err error) { ctx, cancel := context.WithTimeout(context.Background(), s.vaultTimeout) defer cancel() - storedICA, _ := s.vault.Get(ctx, s.certs.VaultKV, "intermediate-ca") + storedICA, err := s.vault.Get(ctx, s.certs.VaultKV, s.certs.CA.CommonName+"-ca") + if err != nil { + zap.L().Error("get", zap.String("mount_path", s.certs.VaultKV), zap.String("secrete_path", s.certs.CA.CommonName+"-ca"), zap.Error(err)) + } if cert != nil { return []byte(storedICA["certificate"].(string)), []byte(storedICA["private_key"].(string)), nil } From dc50f662fc6ec71fb880e38237a5195de740401f Mon Sep 17 00:00:00 2001 From: irbgeo Date: Wed, 15 Jun 2022 10:33:24 +0300 Subject: [PATCH 016/220] fix gereate intermediate ca | genereate simple cert --- README.md | 4 + internal/controller/certificate.go | 15 +-- internal/controller/controller.go | 160 ++++++++++++++++------------- internal/controller/types.go | 5 + 4 files changed, 108 insertions(+), 76 deletions(-) diff --git a/README.md b/README.md index 2bdff54..af6bb52 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,10 @@ certificates: ca: common_name: "common_name" host_path: "path for store of ca in host" + cert: + common_name: "common_name" + role: "role for generate cert" + host_path: "path for store of ca in host" ``` Build: diff --git a/internal/controller/certificate.go b/internal/controller/certificate.go index 06887af..3b3a461 100644 --- a/internal/controller/certificate.go +++ b/internal/controller/certificate.go @@ -7,14 +7,11 @@ import ( "os" ) -func (s *controller) storeCertificate(path string, cert []byte) error { +func (s *controller) storeCertificate(path string, cert, key []byte) error { if err := os.WriteFile(path+".pem", cert, 0644); err != nil { return fmt.Errorf("failed to save certificate with path %s: %w", path, err) } - return nil -} -func (s *controller) storeKey(path string, key []byte) error { if err := os.WriteFile(path+"-key.pem", key, 0600); err != nil { return fmt.Errorf("failed to save key file: %w", err) } @@ -22,17 +19,21 @@ func (s *controller) storeKey(path string, key []byte) error { } func (s *controller) readCertificate(path string) (*tls.Certificate, error) { - crtContent, err := os.ReadFile(path + ".pem") + crt, err := os.ReadFile(path + ".pem") if err != nil { return nil, err } - keyContent, err := os.ReadFile(path + "-key.pem") + key, err := os.ReadFile(path + "-key.pem") if err != nil { return nil, err } + return parseToCert(crt, key) + +} - cert, err := tls.X509KeyPair(crtContent, keyContent) +func parseToCert(crt, key []byte) (*tls.Certificate, error) { + cert, err := tls.X509KeyPair(crt, key) if err != nil { return nil, fmt.Errorf("failed to parse x509 key pair: %w", err) } diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 9cd9a0b..27aa2ce 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -2,7 +2,9 @@ package controller import ( "context" + "crypto/tls" "fmt" + "os" "time" "go.uber.org/zap" @@ -37,13 +39,17 @@ func New(store vault, cfg Config) *controller { } func (s *controller) TurnOn() error { - // cert, err := s.readCertificate(s.domainName) - // if cert != nil && time.Until(cert.Leaf.NotAfter) > s.validInterval { - // return nil - // } - // if err != nil && !os.IsNotExist(err) { - // return err - // } + defer func() { + go s.runtime() + }() + + cert, err := s.readCertificate(s.certs.Cert.HostPath) + if cert != nil && time.Until(cert.Leaf.NotAfter) > s.certs.ValidInterval { + return nil + } + if err != nil && !os.IsNotExist(err) { + return err + } //create intermediate CA with common name example.com icaCert, icaKey, err := s.GenerateIntermediateCA() @@ -51,42 +57,51 @@ func (s *controller) TurnOn() error { return err } - if err := s.storeCertificate(s.certs.CA.HostPath, icaCert); err != nil { + if err := s.storeCertificate(s.certs.CA.HostPath, icaCert, icaKey); err != nil { return err } - if err := s.storeKey(s.certs.CA.HostPath, icaKey); err != nil { + certData, keyData, err := s.GenerateCert() + if err != nil { + return err + } + if err := s.storeCertificate(s.certs.Cert.HostPath, certData, keyData); err != nil { return err } - - // ctx, cancel = context.WithTimeout(context.Background(), s.vaultTimeout) - // defer cancel() - // certData, keyData, err := s.GenerateCert(ctx) - // if err != nil { - // return err - // } - // if err := s.storeCertificate(s.certPath, certData); err != nil { - // return err - // } - // if err := s.storeKey(s.keyPath, keyData); err != nil { - // return err - // } - - // go s.runtime() return nil } -func (s *controller) GenerateIntermediateCA() (cert []byte, key []byte, err error) { +func (s *controller) GenerateIntermediateCA() (crt []byte, key []byte, err error) { ctx, cancel := context.WithTimeout(context.Background(), s.vaultTimeout) defer cancel() storedICA, err := s.vault.Get(ctx, s.certs.VaultKV, s.certs.CA.CommonName+"-ca") if err != nil { - zap.L().Error("get", zap.String("mount_path", s.certs.VaultKV), zap.String("secrete_path", s.certs.CA.CommonName+"-ca"), zap.Error(err)) + zap.L().Error( + "getting", + zap.Any("certificate", "intermediate-ca"), + zap.String("mount_path", s.certs.VaultKV), + zap.String("secrete_path", s.certs.CA.CommonName+"-ca"), + zap.Error(err), + ) } - if cert != nil { - return []byte(storedICA["certificate"].(string)), []byte(storedICA["private_key"].(string)), nil + if storedICA != nil { + crt, key = []byte(storedICA["certificate"].(string)), []byte(storedICA["private_key"].(string)) + var cert *tls.Certificate + cert, err = parseToCert(crt, key) + if cert != nil && time.Until(cert.Leaf.NotAfter) < s.certs.ValidInterval { + err = fmt.Errorf("the certificate expires after %f h.", time.Until(cert.Leaf.NotAfter).Hours()) + } + if err != nil { + zap.L().Error( + "analize", + zap.Any("certificate", "intermediate-ca"), + zap.Error(err), + ) + } + if err == nil { + return + } } - //TODO: check expire // create intermediate CA ctx, cancel = context.WithTimeout(context.Background(), s.vaultTimeout) @@ -99,6 +114,7 @@ func (s *controller) GenerateIntermediateCA() (cert []byte, key []byte, err erro csr, err := s.vault.Write(ctx, s.certs.CertPath+"/intermediate/generate/exported", csrData) if err != nil { + err = fmt.Errorf("create intermediate CA: %w", err) return } @@ -114,6 +130,7 @@ func (s *controller) GenerateIntermediateCA() (cert []byte, key []byte, err erro ica, err := s.vault.Write(ctx, s.certs.RootPath+"/root/sign-intermediate", icaData) if err != nil { + err = fmt.Errorf("send the intermediate CA's CSR to the root CA for signing CA: %w", err) return } @@ -126,56 +143,61 @@ func (s *controller) GenerateIntermediateCA() (cert []byte, key []byte, err erro } if _, err = s.vault.Write(ctx, s.certs.CertPath+"/intermediate/set-signed", certData); err != nil { + err = fmt.Errorf("publish the signed certificate back to the Intermediate CA: %w", err) return } - ctx, cancel = context.WithTimeout(context.Background(), s.vaultTimeout) - defer cancel() - + // saving the created Intermediate CA storedICA = map[string]interface{}{ "certificate": ica["certificate"], "private_key": csr["private_key"], } if err = s.vault.Put(ctx, s.certs.VaultKV, "intermediate-ca", storedICA); err != nil { + err = fmt.Errorf("saving the created Intermediate CA: %w", err) return } return []byte(ica["certificate"].(string)), []byte(csr["private_key"].(string)), nil } -// func (s *controller) GenerateCert(ctx context.Context) ([]byte, []byte, error) { -// certData := map[string]interface{}{ -// "common_name": s.domainName, -// } -// cert, err := s.vault.Write(ctx, s.vaultCertPath, certData) -// if err != nil { -// return nil, nil, err -// } -// return cert["certificate"].([]byte), cert["private_key"].([]byte), nil -// } - -// func (s *controller) runtime() { -// t := time.Tick(time.Hour) -// for { -// select { -// case <-t: -// cert, err := s.readCertificate(s.domainName) -// if cert == nil || time.Until(cert.Leaf.NotAfter) < s.validInterval { -// ctx, cancel := context.WithTimeout(context.Background(), s.vaultTimeout) -// certData, keyData, err := s.GenerateCert(ctx) -// if err != nil { -// zap.L().Error("generate certificate", zap.Error(err)) -// } -// cancel() -// if err := s.storeCertificate(s.certPath, certData); err != nil { -// zap.L().Error("store certificate", zap.Error(err)) -// } -// if err := s.storeKey(s.keyPath, keyData); err != nil { -// zap.L().Error("store key", zap.Error(err)) -// } -// } -// if err != nil { -// zap.L().Error("read certificate", zap.Error(err)) -// } -// } -// } -// } +func (s *controller) GenerateCert() ([]byte, []byte, error) { + ctx, cancel := context.WithTimeout(context.Background(), s.vaultTimeout) + defer cancel() + + certData := map[string]interface{}{ + "common_name": s.certs.Cert.CommonName, + } + cert, err := s.vault.Write(ctx, s.certs.CertPath+"/issue/"+s.certs.Cert.Role, certData) + if err != nil { + return nil, nil, err + } + return []byte(cert["certificate"].(string)), []byte(cert["private_key"].(string)), nil +} + +func (s *controller) runtime() { + t := time.Tick(time.Hour) + for { + select { + case <-t: + cert, err := s.readCertificate(s.certs.Cert.HostPath) + if cert == nil || time.Until(cert.Leaf.NotAfter) < s.certs.ValidInterval { + certData, keyData, err := s.GenerateCert() + if err != nil { + zap.L().Error( + "generate certificate", + zap.Error(err), + ) + } + if err := s.storeCertificate(s.certs.Cert.HostPath, certData, keyData); err != nil { + zap.L().Error( + "store certificate", + zap.String("path", s.certs.Cert.HostPath), + zap.Error(err), + ) + } + } + if err != nil { + zap.L().Error("read certificate", zap.Error(err)) + } + } + } +} diff --git a/internal/controller/types.go b/internal/controller/types.go index 35706c8..16e0020 100644 --- a/internal/controller/types.go +++ b/internal/controller/types.go @@ -24,4 +24,9 @@ type Certificates struct { CommonName string `yaml:"common_name"` HostPath string `yaml:"host_path"` } `yaml:"ca"` + Cert struct { + CommonName string `yaml:"common_name"` + Role string `yaml:"role"` + HostPath string `yaml:"host_path"` + } `yaml:"cert"` } From e8af9fa5efdb6fc61f854fcf7a795a4af72a6b82 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Wed, 15 Jun 2022 12:09:25 +0300 Subject: [PATCH 017/220] update --- README.md | 2 +- internal/controller/controller.go | 14 +++++++------- internal/controller/types.go | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index af6bb52..10738af 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ certificates: ca: common_name: "common_name" host_path: "path for store of ca in host" - cert: + csr: common_name: "common_name" role: "role for generate cert" host_path: "path for store of ca in host" diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 27aa2ce..336aa30 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -43,7 +43,7 @@ func (s *controller) TurnOn() error { go s.runtime() }() - cert, err := s.readCertificate(s.certs.Cert.HostPath) + cert, err := s.readCertificate(s.certs.CSR.HostPath) if cert != nil && time.Until(cert.Leaf.NotAfter) > s.certs.ValidInterval { return nil } @@ -65,7 +65,7 @@ func (s *controller) TurnOn() error { if err != nil { return err } - if err := s.storeCertificate(s.certs.Cert.HostPath, certData, keyData); err != nil { + if err := s.storeCertificate(s.certs.CSR.HostPath, certData, keyData); err != nil { return err } return nil @@ -164,9 +164,9 @@ func (s *controller) GenerateCert() ([]byte, []byte, error) { defer cancel() certData := map[string]interface{}{ - "common_name": s.certs.Cert.CommonName, + "common_name": s.certs.CSR.CommonName, } - cert, err := s.vault.Write(ctx, s.certs.CertPath+"/issue/"+s.certs.Cert.Role, certData) + cert, err := s.vault.Write(ctx, s.certs.CertPath+"/issue/"+s.certs.CSR.Role, certData) if err != nil { return nil, nil, err } @@ -178,7 +178,7 @@ func (s *controller) runtime() { for { select { case <-t: - cert, err := s.readCertificate(s.certs.Cert.HostPath) + cert, err := s.readCertificate(s.certs.CSR.HostPath) if cert == nil || time.Until(cert.Leaf.NotAfter) < s.certs.ValidInterval { certData, keyData, err := s.GenerateCert() if err != nil { @@ -187,10 +187,10 @@ func (s *controller) runtime() { zap.Error(err), ) } - if err := s.storeCertificate(s.certs.Cert.HostPath, certData, keyData); err != nil { + if err := s.storeCertificate(s.certs.CSR.HostPath, certData, keyData); err != nil { zap.L().Error( "store certificate", - zap.String("path", s.certs.Cert.HostPath), + zap.String("path", s.certs.CSR.HostPath), zap.Error(err), ) } diff --git a/internal/controller/types.go b/internal/controller/types.go index 16e0020..e81b766 100644 --- a/internal/controller/types.go +++ b/internal/controller/types.go @@ -24,9 +24,9 @@ type Certificates struct { CommonName string `yaml:"common_name"` HostPath string `yaml:"host_path"` } `yaml:"ca"` - Cert struct { + CSR struct { CommonName string `yaml:"common_name"` Role string `yaml:"role"` HostPath string `yaml:"host_path"` - } `yaml:"cert"` + } `yaml:"csr"` } From 6a753d6f44512cc856cbf4a7c914a1aa98323815 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Wed, 15 Jun 2022 16:30:54 +0300 Subject: [PATCH 018/220] option certs --- internal/controller/ca.go | 128 ++++++++++++ internal/controller/controller.go | 183 ++---------------- internal/controller/csr.go | 57 ++++++ .../controller/{certificate.go => store.go} | 0 internal/controller/types.go | 8 +- 5 files changed, 209 insertions(+), 167 deletions(-) create mode 100644 internal/controller/ca.go create mode 100644 internal/controller/csr.go rename internal/controller/{certificate.go => store.go} (100%) diff --git a/internal/controller/ca.go b/internal/controller/ca.go new file mode 100644 index 0000000..bf69f02 --- /dev/null +++ b/internal/controller/ca.go @@ -0,0 +1,128 @@ +package controller + +import ( + "context" + "crypto/tls" + "fmt" + "time" + + "go.uber.org/zap" +) + +func (s *controller) CA() error { + ctx, cancel := context.WithTimeout(context.Background(), s.cfg.Vault.Timeout) + defer cancel() + storedICA, err := s.vault.Get(ctx, s.cfg.Certs.VaultKV, s.cfg.Certs.CA.CommonName+"-ca") + if err != nil { + + return err + } + if storedICA != nil { + cert, key := []byte(storedICA["certificate"].(string)), []byte(storedICA["private_key"].(string)) + var ca *tls.Certificate + ca, err = parseToCert(cert, key) + if ca != nil && time.Until(ca.Leaf.NotAfter) < s.cfg.Certs.ValidInterval { + zap.L().Warn( + "expired intermediate-ca", + zap.Float64("until_h", time.Until(ca.Leaf.NotAfter).Hours()), + zap.Error(err), + ) + } + if err != nil { + zap.L().Error( + "analize", + zap.Any("certificate", "intermediate-ca"), + zap.Error(err), + ) + return err + } + if err == nil { + return nil + } + } + + cert, key, err := s.GenerateIntermediateCA() + if err != nil { + zap.L().Error( + "generate intermediate-ca", + zap.Error(err), + ) + return err + } + + if err = s.StoreCA(cert, key); err != nil { + zap.L().Error( + "stored intermediate-ca", + zap.Error(err), + ) + return err + } + + return nil +} +func (s *controller) GenerateIntermediateCA() (crt, key []byte, err error) { + // create intermediate CA + ctx, cancel := context.WithTimeout(context.Background(), s.cfg.Vault.Timeout) + defer cancel() + + csrData := map[string]interface{}{ + "common_name": fmt.Sprintf(intermediateCommonNameLayout, s.cfg.Certs.CA.CommonName), + "ttl": "8760h", + } + + csr, err := s.vault.Write(ctx, s.cfg.Certs.CertPath+"/intermediate/generate/exported", csrData) + if err != nil { + err = fmt.Errorf("create intermediate CA: %w", err) + return + } + + // send the intermediate CA's CSR to the root CA for signing + ctx, cancel = context.WithTimeout(context.Background(), s.cfg.Vault.Timeout) + defer cancel() + + icaData := map[string]interface{}{ + "csr": csr["csr"], + "format": "pem_bundle", + "ttl": "8760h", + } + + ica, err := s.vault.Write(ctx, s.cfg.Certs.RootPath+"/root/sign-intermediate", icaData) + if err != nil { + err = fmt.Errorf("send the intermediate CA's CSR to the root CA for signing CA: %w", err) + return + } + + // publish the signed certificate back to the Intermediate CA + ctx, cancel = context.WithTimeout(context.Background(), s.cfg.Vault.Timeout) + defer cancel() + + certData := map[string]interface{}{ + "certificate": ica["certificate"], + } + + if _, err = s.vault.Write(ctx, s.cfg.Certs.CertPath+"/intermediate/set-signed", certData); err != nil { + err = fmt.Errorf("publish the signed certificate back to the Intermediate CA: %w", err) + return + } + + return []byte(ica["certificate"].(string)), []byte(csr["private_key"].(string)), nil +} + +func (s *controller) StoreCA(crt, key []byte) error { + ctx, cancel := context.WithTimeout(context.Background(), s.cfg.Vault.Timeout) + defer cancel() + // saving the created Intermediate CA + storedICA := map[string]interface{}{ + "certificate": crt, + "private_key": key, + } + if err := s.vault.Put(ctx, s.cfg.Certs.VaultKV, "intermediate-ca", storedICA); err != nil { + return fmt.Errorf("saving in vault: %w", err) + } + + if err := s.storeCertificate(s.cfg.Certs.CA.HostPath, crt, key); err != nil { + return fmt.Errorf("host path %s : %w", s.cfg.Certs.CA.HostPath, err) + + } + return nil +} diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 336aa30..ff01d72 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -2,12 +2,7 @@ package controller import ( "context" - "crypto/tls" - "fmt" - "os" "time" - - "go.uber.org/zap" ) var intermediateCommonNameLayout = "%s Intermediate Authority" @@ -23,181 +18,43 @@ type vault interface { type controller struct { vault vault - vaultTimeout time.Duration + cfg Config - certs Certificates + certs []func() error } func New(store vault, cfg Config) *controller { c := &controller{ vault: store, - vaultTimeout: cfg.Vault.Timeout, - certs: cfg.Certs, - } - return c -} - -func (s *controller) TurnOn() error { - defer func() { - go s.runtime() - }() - - cert, err := s.readCertificate(s.certs.CSR.HostPath) - if cert != nil && time.Until(cert.Leaf.NotAfter) > s.certs.ValidInterval { - return nil - } - if err != nil && !os.IsNotExist(err) { - return err - } - - //create intermediate CA with common name example.com - icaCert, icaKey, err := s.GenerateIntermediateCA() - if err != nil { - return err - } - - if err := s.storeCertificate(s.certs.CA.HostPath, icaCert, icaKey); err != nil { - return err + cfg: cfg, } - certData, keyData, err := s.GenerateCert() - if err != nil { - return err + if cfg.Certs.CA != nil { + c.certs = append(c.certs, c.CA) } - if err := s.storeCertificate(s.certs.CSR.HostPath, certData, keyData); err != nil { - return err + if cfg.Certs.CSR != nil { + c.certs = append(c.certs, c.CSR) } - return nil + return c } -func (s *controller) GenerateIntermediateCA() (crt []byte, key []byte, err error) { - ctx, cancel := context.WithTimeout(context.Background(), s.vaultTimeout) - defer cancel() - storedICA, err := s.vault.Get(ctx, s.certs.VaultKV, s.certs.CA.CommonName+"-ca") - if err != nil { - zap.L().Error( - "getting", - zap.Any("certificate", "intermediate-ca"), - zap.String("mount_path", s.certs.VaultKV), - zap.String("secrete_path", s.certs.CA.CommonName+"-ca"), - zap.Error(err), - ) - } - if storedICA != nil { - crt, key = []byte(storedICA["certificate"].(string)), []byte(storedICA["private_key"].(string)) - var cert *tls.Certificate - cert, err = parseToCert(crt, key) - if cert != nil && time.Until(cert.Leaf.NotAfter) < s.certs.ValidInterval { - err = fmt.Errorf("the certificate expires after %f h.", time.Until(cert.Leaf.NotAfter).Hours()) - } - if err != nil { - zap.L().Error( - "analize", - zap.Any("certificate", "intermediate-ca"), - zap.Error(err), - ) - } - if err == nil { - return +func (s *controller) TurnOn() error { + for _, f := range s.certs { + if err := f(); err != nil { + return err } } - // create intermediate CA - ctx, cancel = context.WithTimeout(context.Background(), s.vaultTimeout) - defer cancel() - - csrData := map[string]interface{}{ - "common_name": fmt.Sprintf(intermediateCommonNameLayout, s.certs.CA.CommonName), - "ttl": "8760h", - } - - csr, err := s.vault.Write(ctx, s.certs.CertPath+"/intermediate/generate/exported", csrData) - if err != nil { - err = fmt.Errorf("create intermediate CA: %w", err) - return - } - - // send the intermediate CA's CSR to the root CA for signing - ctx, cancel = context.WithTimeout(context.Background(), s.vaultTimeout) - defer cancel() - - icaData := map[string]interface{}{ - "csr": csr["csr"], - "format": "pem_bundle", - "ttl": "8760h", - } - - ica, err := s.vault.Write(ctx, s.certs.RootPath+"/root/sign-intermediate", icaData) - if err != nil { - err = fmt.Errorf("send the intermediate CA's CSR to the root CA for signing CA: %w", err) - return - } - - // publish the signed certificate back to the Intermediate CA - ctx, cancel = context.WithTimeout(context.Background(), s.vaultTimeout) - defer cancel() - - certData := map[string]interface{}{ - "certificate": ica["certificate"], - } - - if _, err = s.vault.Write(ctx, s.certs.CertPath+"/intermediate/set-signed", certData); err != nil { - err = fmt.Errorf("publish the signed certificate back to the Intermediate CA: %w", err) - return - } - - // saving the created Intermediate CA - storedICA = map[string]interface{}{ - "certificate": ica["certificate"], - "private_key": csr["private_key"], - } - if err = s.vault.Put(ctx, s.certs.VaultKV, "intermediate-ca", storedICA); err != nil { - err = fmt.Errorf("saving the created Intermediate CA: %w", err) - return - } - return []byte(ica["certificate"].(string)), []byte(csr["private_key"].(string)), nil -} - -func (s *controller) GenerateCert() ([]byte, []byte, error) { - ctx, cancel := context.WithTimeout(context.Background(), s.vaultTimeout) - defer cancel() - - certData := map[string]interface{}{ - "common_name": s.certs.CSR.CommonName, - } - cert, err := s.vault.Write(ctx, s.certs.CertPath+"/issue/"+s.certs.CSR.Role, certData) - if err != nil { - return nil, nil, err - } - return []byte(cert["certificate"].(string)), []byte(cert["private_key"].(string)), nil -} - -func (s *controller) runtime() { - t := time.Tick(time.Hour) - for { - select { - case <-t: - cert, err := s.readCertificate(s.certs.CSR.HostPath) - if cert == nil || time.Until(cert.Leaf.NotAfter) < s.certs.ValidInterval { - certData, keyData, err := s.GenerateCert() - if err != nil { - zap.L().Error( - "generate certificate", - zap.Error(err), - ) - } - if err := s.storeCertificate(s.certs.CSR.HostPath, certData, keyData); err != nil { - zap.L().Error( - "store certificate", - zap.String("path", s.certs.CSR.HostPath), - zap.Error(err), - ) - } - } - if err != nil { - zap.L().Error("read certificate", zap.Error(err)) + t := time.NewTicker(time.Hour) + defer t.Stop() + for range t.C { + for _, f := range s.certs { + if err := f(); err != nil { + return err } } } + + return nil } diff --git a/internal/controller/csr.go b/internal/controller/csr.go new file mode 100644 index 0000000..ceb4e00 --- /dev/null +++ b/internal/controller/csr.go @@ -0,0 +1,57 @@ +package controller + +import ( + "context" + "fmt" + "os" + "time" + + "go.uber.org/zap" +) + +func (s *controller) CSR() error { + csr, err := s.readCertificate(s.cfg.Certs.CSR.HostPath) + if csr != nil && time.Until(csr.Leaf.NotAfter) > s.cfg.Certs.ValidInterval { + return nil + } + if err != nil && !os.IsNotExist(err) { + zap.L().Error("read csr", zap.String("path", s.cfg.Certs.CSR.HostPath), zap.Error(err)) + return err + } + + cert, key, err := s.GenerateCSR() + if err != nil { + zap.L().Error("generate csr", zap.Error(err)) + return err + } + + err = s.StoreCSR(cert, key) + if err != nil { + zap.L().Error("store csr", zap.Error(err)) + return err + } + + return err +} + +func (s *controller) GenerateCSR() ([]byte, []byte, error) { + ctx, cancel := context.WithTimeout(context.Background(), s.cfg.Vault.Timeout) + defer cancel() + + certData := map[string]interface{}{ + "common_name": s.cfg.Certs.CSR.CommonName, + } + path := s.cfg.Certs.CertPath + "/issue/" + s.cfg.Certs.CSR.Role + cert, err := s.vault.Write(ctx, path, certData) + if err != nil { + return nil, nil, fmt.Errorf("generate with path %s : %w", path, err) + } + return []byte(cert["certificate"].(string)), []byte(cert["private_key"].(string)), nil +} + +func (s *controller) StoreCSR(cert, key []byte) error { + if err := s.storeCertificate(s.cfg.Certs.CSR.HostPath, cert, key); err != nil { + return fmt.Errorf("host path %s : %w", s.cfg.Certs.CSR.HostPath, err) + } + return nil +} diff --git a/internal/controller/certificate.go b/internal/controller/store.go similarity index 100% rename from internal/controller/certificate.go rename to internal/controller/store.go diff --git a/internal/controller/types.go b/internal/controller/types.go index e81b766..46b4c3e 100644 --- a/internal/controller/types.go +++ b/internal/controller/types.go @@ -20,13 +20,13 @@ type Certificates struct { CertPath string `yaml:"cert_path"` VaultKV string `yaml:"vault_kv"` ValidInterval time.Duration `yaml:"valid_interval"` - CA struct { + CA *struct { CommonName string `yaml:"common_name"` HostPath string `yaml:"host_path"` - } `yaml:"ca"` - CSR struct { + } `yaml:"ca,omitempty"` + CSR *struct { CommonName string `yaml:"common_name"` Role string `yaml:"role"` HostPath string `yaml:"host_path"` - } `yaml:"csr"` + } `yaml:"csr,omitempty"` } From bca34e94971fded92c0dd7208b370cd08c1f603f Mon Sep 17 00:00:00 2001 From: irbgeo Date: Wed, 15 Jun 2022 17:08:23 +0300 Subject: [PATCH 019/220] fix --- internal/controller/ca.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/internal/controller/ca.go b/internal/controller/ca.go index bf69f02..63b5e68 100644 --- a/internal/controller/ca.go +++ b/internal/controller/ca.go @@ -14,8 +14,12 @@ func (s *controller) CA() error { defer cancel() storedICA, err := s.vault.Get(ctx, s.cfg.Certs.VaultKV, s.cfg.Certs.CA.CommonName+"-ca") if err != nil { - - return err + zap.L().Warn( + "get intermediate ca", + zap.String("name", s.cfg.Certs.CA.CommonName+"-ca"), + zap.String("vault_kv", s.cfg.Certs.VaultKV), + zap.Error(err), + ) } if storedICA != nil { cert, key := []byte(storedICA["certificate"].(string)), []byte(storedICA["private_key"].(string)) @@ -116,7 +120,7 @@ func (s *controller) StoreCA(crt, key []byte) error { "certificate": crt, "private_key": key, } - if err := s.vault.Put(ctx, s.cfg.Certs.VaultKV, "intermediate-ca", storedICA); err != nil { + if err := s.vault.Put(ctx, s.cfg.Certs.VaultKV, s.cfg.Certs.CA.CommonName+"-ca", storedICA); err != nil { return fmt.Errorf("saving in vault: %w", err) } From 72f1ba774d59f26384f7ec32a064f682c9c731af Mon Sep 17 00:00:00 2001 From: irbgeo Date: Wed, 15 Jun 2022 18:03:59 +0300 Subject: [PATCH 020/220] add slice of certs --- README.md | 10 ++++----- internal/controller/ca.go | 22 +++++++++---------- internal/controller/controller.go | 35 ++++++++++++++++--------------- internal/controller/csr.go | 22 +++++++++---------- internal/controller/types.go | 22 +++++++++++-------- 5 files changed, 58 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 10738af..a09c9e6 100644 --- a/README.md +++ b/README.md @@ -13,12 +13,12 @@ certificates: vault_kv: "path for kv" valid_interval: "valid expire cert interval: 1s, 3m, 5h" ca: - common_name: "common_name" - host_path: "path for store of ca in host" + - common_name: "common_name" + host_path: "path for store of ca in host" csr: - common_name: "common_name" - role: "role for generate cert" - host_path: "path for store of ca in host" + - common_name: "common_name" + role: "role for generate cert" + host_path: "path for store of ca in host" ``` Build: diff --git a/internal/controller/ca.go b/internal/controller/ca.go index 63b5e68..a7c9c38 100644 --- a/internal/controller/ca.go +++ b/internal/controller/ca.go @@ -9,14 +9,14 @@ import ( "go.uber.org/zap" ) -func (s *controller) CA() error { +func (s *controller) CA(i CA) error { ctx, cancel := context.WithTimeout(context.Background(), s.cfg.Vault.Timeout) defer cancel() - storedICA, err := s.vault.Get(ctx, s.cfg.Certs.VaultKV, s.cfg.Certs.CA.CommonName+"-ca") + storedICA, err := s.vault.Get(ctx, s.cfg.Certs.VaultKV, i.CommonName+"-ca") if err != nil { zap.L().Warn( "get intermediate ca", - zap.String("name", s.cfg.Certs.CA.CommonName+"-ca"), + zap.String("name", i.CommonName+"-ca"), zap.String("vault_kv", s.cfg.Certs.VaultKV), zap.Error(err), ) @@ -45,7 +45,7 @@ func (s *controller) CA() error { } } - cert, key, err := s.GenerateIntermediateCA() + cert, key, err := s.GenerateIntermediateCA(i) if err != nil { zap.L().Error( "generate intermediate-ca", @@ -54,7 +54,7 @@ func (s *controller) CA() error { return err } - if err = s.StoreCA(cert, key); err != nil { + if err = s.StoreCA(i, cert, key); err != nil { zap.L().Error( "stored intermediate-ca", zap.Error(err), @@ -64,13 +64,13 @@ func (s *controller) CA() error { return nil } -func (s *controller) GenerateIntermediateCA() (crt, key []byte, err error) { +func (s *controller) GenerateIntermediateCA(i CA) (crt, key []byte, err error) { // create intermediate CA ctx, cancel := context.WithTimeout(context.Background(), s.cfg.Vault.Timeout) defer cancel() csrData := map[string]interface{}{ - "common_name": fmt.Sprintf(intermediateCommonNameLayout, s.cfg.Certs.CA.CommonName), + "common_name": fmt.Sprintf(intermediateCommonNameLayout, i.CommonName), "ttl": "8760h", } @@ -112,7 +112,7 @@ func (s *controller) GenerateIntermediateCA() (crt, key []byte, err error) { return []byte(ica["certificate"].(string)), []byte(csr["private_key"].(string)), nil } -func (s *controller) StoreCA(crt, key []byte) error { +func (s *controller) StoreCA(i CA, crt, key []byte) error { ctx, cancel := context.WithTimeout(context.Background(), s.cfg.Vault.Timeout) defer cancel() // saving the created Intermediate CA @@ -120,12 +120,12 @@ func (s *controller) StoreCA(crt, key []byte) error { "certificate": crt, "private_key": key, } - if err := s.vault.Put(ctx, s.cfg.Certs.VaultKV, s.cfg.Certs.CA.CommonName+"-ca", storedICA); err != nil { + if err := s.vault.Put(ctx, s.cfg.Certs.VaultKV, i.CommonName+"-ca", storedICA); err != nil { return fmt.Errorf("saving in vault: %w", err) } - if err := s.storeCertificate(s.cfg.Certs.CA.HostPath, crt, key); err != nil { - return fmt.Errorf("host path %s : %w", s.cfg.Certs.CA.HostPath, err) + if err := s.storeCertificate(i.HostPath, crt, key); err != nil { + return fmt.Errorf("host path %s : %w", i.HostPath, err) } return nil diff --git a/internal/controller/controller.go b/internal/controller/controller.go index ff01d72..5a0853e 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -19,8 +19,6 @@ type controller struct { vault vault cfg Config - - certs []func() error } func New(store vault, cfg Config) *controller { @@ -29,32 +27,35 @@ func New(store vault, cfg Config) *controller { cfg: cfg, } - - if cfg.Certs.CA != nil { - c.certs = append(c.certs, c.CA) - } - if cfg.Certs.CSR != nil { - c.certs = append(c.certs, c.CSR) - } return c } func (s *controller) TurnOn() error { - for _, f := range s.certs { - if err := f(); err != nil { - return err - } + if err := s.workflow(); err != nil { + return err } t := time.NewTicker(time.Hour) defer t.Stop() for range t.C { - for _, f := range s.certs { - if err := f(); err != nil { - return err - } + if err := s.workflow(); err != nil { + return err } } return nil } + +func (s *controller) workflow() error { + for _, i := range s.cfg.Certs.CA { + if err := s.CA(i); err != nil { + return err + } + } + for _, i := range s.cfg.Certs.CSR { + if err := s.CSR(i); err != nil { + return err + } + } + return nil +} diff --git a/internal/controller/csr.go b/internal/controller/csr.go index ceb4e00..c469486 100644 --- a/internal/controller/csr.go +++ b/internal/controller/csr.go @@ -9,23 +9,23 @@ import ( "go.uber.org/zap" ) -func (s *controller) CSR() error { - csr, err := s.readCertificate(s.cfg.Certs.CSR.HostPath) +func (s *controller) CSR(i CSR) error { + csr, err := s.readCertificate(i.HostPath) if csr != nil && time.Until(csr.Leaf.NotAfter) > s.cfg.Certs.ValidInterval { return nil } if err != nil && !os.IsNotExist(err) { - zap.L().Error("read csr", zap.String("path", s.cfg.Certs.CSR.HostPath), zap.Error(err)) + zap.L().Error("read csr", zap.String("path", i.HostPath), zap.Error(err)) return err } - cert, key, err := s.GenerateCSR() + cert, key, err := s.GenerateCSR(i) if err != nil { zap.L().Error("generate csr", zap.Error(err)) return err } - err = s.StoreCSR(cert, key) + err = s.StoreCSR(i, cert, key) if err != nil { zap.L().Error("store csr", zap.Error(err)) return err @@ -34,14 +34,14 @@ func (s *controller) CSR() error { return err } -func (s *controller) GenerateCSR() ([]byte, []byte, error) { +func (s *controller) GenerateCSR(i CSR) ([]byte, []byte, error) { ctx, cancel := context.WithTimeout(context.Background(), s.cfg.Vault.Timeout) defer cancel() certData := map[string]interface{}{ - "common_name": s.cfg.Certs.CSR.CommonName, + "common_name": i.CommonName, } - path := s.cfg.Certs.CertPath + "/issue/" + s.cfg.Certs.CSR.Role + path := s.cfg.Certs.CertPath + "/issue/" + i.Role cert, err := s.vault.Write(ctx, path, certData) if err != nil { return nil, nil, fmt.Errorf("generate with path %s : %w", path, err) @@ -49,9 +49,9 @@ func (s *controller) GenerateCSR() ([]byte, []byte, error) { return []byte(cert["certificate"].(string)), []byte(cert["private_key"].(string)), nil } -func (s *controller) StoreCSR(cert, key []byte) error { - if err := s.storeCertificate(s.cfg.Certs.CSR.HostPath, cert, key); err != nil { - return fmt.Errorf("host path %s : %w", s.cfg.Certs.CSR.HostPath, err) +func (s *controller) StoreCSR(i CSR, cert, key []byte) error { + if err := s.storeCertificate(i.HostPath, cert, key); err != nil { + return fmt.Errorf("host path %s : %w", i.HostPath, err) } return nil } diff --git a/internal/controller/types.go b/internal/controller/types.go index 46b4c3e..81e581e 100644 --- a/internal/controller/types.go +++ b/internal/controller/types.go @@ -20,13 +20,17 @@ type Certificates struct { CertPath string `yaml:"cert_path"` VaultKV string `yaml:"vault_kv"` ValidInterval time.Duration `yaml:"valid_interval"` - CA *struct { - CommonName string `yaml:"common_name"` - HostPath string `yaml:"host_path"` - } `yaml:"ca,omitempty"` - CSR *struct { - CommonName string `yaml:"common_name"` - Role string `yaml:"role"` - HostPath string `yaml:"host_path"` - } `yaml:"csr,omitempty"` + CA []CA `yaml:"ca,omitempty"` + CSR []CSR `yaml:"csr,omitempty"` +} + +type CA struct { + CommonName string `yaml:"common_name"` + HostPath string `yaml:"host_path"` +} + +type CSR struct { + CommonName string `yaml:"common_name"` + Role string `yaml:"role"` + HostPath string `yaml:"host_path"` } From 3f9d58a852a2255939b599411c46e6a80f915a59 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Wed, 15 Jun 2022 21:13:54 +0300 Subject: [PATCH 021/220] update --- internal/controller/ca.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/internal/controller/ca.go b/internal/controller/ca.go index a7c9c38..8d87353 100644 --- a/internal/controller/ca.go +++ b/internal/controller/ca.go @@ -117,8 +117,8 @@ func (s *controller) StoreCA(i CA, crt, key []byte) error { defer cancel() // saving the created Intermediate CA storedICA := map[string]interface{}{ - "certificate": crt, - "private_key": key, + "certificate": string(crt), + "private_key": string(key), } if err := s.vault.Put(ctx, s.cfg.Certs.VaultKV, i.CommonName+"-ca", storedICA); err != nil { return fmt.Errorf("saving in vault: %w", err) @@ -126,7 +126,6 @@ func (s *controller) StoreCA(i CA, crt, key []byte) error { if err := s.storeCertificate(i.HostPath, crt, key); err != nil { return fmt.Errorf("host path %s : %w", i.HostPath, err) - } return nil } From 28853b2270431cf7a99f6bdb488c17fa6d0a28da Mon Sep 17 00:00:00 2001 From: irbgeo Date: Wed, 15 Jun 2022 23:30:40 +0300 Subject: [PATCH 022/220] up --- internal/controller/ca.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/controller/ca.go b/internal/controller/ca.go index 8d87353..9c74b62 100644 --- a/internal/controller/ca.go +++ b/internal/controller/ca.go @@ -20,6 +20,7 @@ func (s *controller) CA(i CA) error { zap.String("vault_kv", s.cfg.Certs.VaultKV), zap.Error(err), ) + return err } if storedICA != nil { cert, key := []byte(storedICA["certificate"].(string)), []byte(storedICA["private_key"].(string)) @@ -38,7 +39,6 @@ func (s *controller) CA(i CA) error { zap.Any("certificate", "intermediate-ca"), zap.Error(err), ) - return err } if err == nil { return nil From 4b176e5c3d9dcf7003a5f7bd5dad2803e5c48d53 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Wed, 15 Jun 2022 23:38:07 +0300 Subject: [PATCH 023/220] fix --- internal/controller/ca.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/controller/ca.go b/internal/controller/ca.go index 9c74b62..ad81f82 100644 --- a/internal/controller/ca.go +++ b/internal/controller/ca.go @@ -13,14 +13,13 @@ func (s *controller) CA(i CA) error { ctx, cancel := context.WithTimeout(context.Background(), s.cfg.Vault.Timeout) defer cancel() storedICA, err := s.vault.Get(ctx, s.cfg.Certs.VaultKV, i.CommonName+"-ca") - if err != nil { + if err != err{ zap.L().Warn( "get intermediate ca", zap.String("name", i.CommonName+"-ca"), zap.String("vault_kv", s.cfg.Certs.VaultKV), zap.Error(err), ) - return err } if storedICA != nil { cert, key := []byte(storedICA["certificate"].(string)), []byte(storedICA["private_key"].(string)) From cb121e8bd9d635aa6aef8c93a05e89396a82bc9f Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 16 Jun 2022 00:28:07 +0300 Subject: [PATCH 024/220] update --- README.md | 4 ++-- internal/controller/ca.go | 5 +++-- internal/controller/controller.go | 13 ++++++------- internal/controller/types.go | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index a09c9e6..b4f0b23 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,8 @@ certificates: vault_kv: "path for kv" valid_interval: "valid expire cert interval: 1s, 3m, 5h" ca: - - common_name: "common_name" - host_path: "path for store of ca in host" + common_name: "common_name" + host_path: "path for store of ca in host" csr: - common_name: "common_name" role: "role for generate cert" diff --git a/internal/controller/ca.go b/internal/controller/ca.go index ad81f82..b738c1a 100644 --- a/internal/controller/ca.go +++ b/internal/controller/ca.go @@ -13,7 +13,7 @@ func (s *controller) CA(i CA) error { ctx, cancel := context.WithTimeout(context.Background(), s.cfg.Vault.Timeout) defer cancel() storedICA, err := s.vault.Get(ctx, s.cfg.Certs.VaultKV, i.CommonName+"-ca") - if err != err{ + if err != err { zap.L().Warn( "get intermediate ca", zap.String("name", i.CommonName+"-ca"), @@ -103,7 +103,8 @@ func (s *controller) GenerateIntermediateCA(i CA) (crt, key []byte, err error) { "certificate": ica["certificate"], } - if _, err = s.vault.Write(ctx, s.cfg.Certs.CertPath+"/intermediate/set-signed", certData); err != nil { + path := s.cfg.Certs.CertPath + "/intermediate/set-signed" + if _, err = s.vault.Write(ctx, path, certData); err != nil { err = fmt.Errorf("publish the signed certificate back to the Intermediate CA: %w", err) return } diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 5a0853e..fa65057 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -31,14 +31,14 @@ func New(store vault, cfg Config) *controller { } func (s *controller) TurnOn() error { - if err := s.workflow(); err != nil { + if err := s.Workflow(); err != nil { return err } t := time.NewTicker(time.Hour) defer t.Stop() for range t.C { - if err := s.workflow(); err != nil { + if err := s.Workflow(); err != nil { return err } } @@ -46,12 +46,11 @@ func (s *controller) TurnOn() error { return nil } -func (s *controller) workflow() error { - for _, i := range s.cfg.Certs.CA { - if err := s.CA(i); err != nil { - return err - } +func (s *controller) Workflow() error { + if err := s.CA(s.cfg.Certs.CA); err != nil { + return err } + for _, i := range s.cfg.Certs.CSR { if err := s.CSR(i); err != nil { return err diff --git a/internal/controller/types.go b/internal/controller/types.go index 81e581e..e2587db 100644 --- a/internal/controller/types.go +++ b/internal/controller/types.go @@ -20,7 +20,7 @@ type Certificates struct { CertPath string `yaml:"cert_path"` VaultKV string `yaml:"vault_kv"` ValidInterval time.Duration `yaml:"valid_interval"` - CA []CA `yaml:"ca,omitempty"` + CA CA `yaml:"ca,omitempty"` CSR []CSR `yaml:"csr,omitempty"` } From 20b0053ed0a21cf640346ae683667ced35535b4a Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 16 Jun 2022 11:26:05 +0300 Subject: [PATCH 025/220] update --- internal/controller/ca.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/internal/controller/ca.go b/internal/controller/ca.go index b738c1a..ed46309 100644 --- a/internal/controller/ca.go +++ b/internal/controller/ca.go @@ -73,7 +73,8 @@ func (s *controller) GenerateIntermediateCA(i CA) (crt, key []byte, err error) { "ttl": "8760h", } - csr, err := s.vault.Write(ctx, s.cfg.Certs.CertPath+"/intermediate/generate/exported", csrData) + path := s.cfg.Certs.CertPath + "/intermediate/generate/exported" + csr, err := s.vault.Write(ctx, path, csrData) if err != nil { err = fmt.Errorf("create intermediate CA: %w", err) return @@ -89,7 +90,8 @@ func (s *controller) GenerateIntermediateCA(i CA) (crt, key []byte, err error) { "ttl": "8760h", } - ica, err := s.vault.Write(ctx, s.cfg.Certs.RootPath+"/root/sign-intermediate", icaData) + path = s.cfg.Certs.RootPath + "/root/sign-intermediate" + ica, err := s.vault.Write(ctx, path, icaData) if err != nil { err = fmt.Errorf("send the intermediate CA's CSR to the root CA for signing CA: %w", err) return @@ -103,7 +105,7 @@ func (s *controller) GenerateIntermediateCA(i CA) (crt, key []byte, err error) { "certificate": ica["certificate"], } - path := s.cfg.Certs.CertPath + "/intermediate/set-signed" + path = s.cfg.Certs.CertPath + "/intermediate/set-signed" if _, err = s.vault.Write(ctx, path, certData); err != nil { err = fmt.Errorf("publish the signed certificate back to the Intermediate CA: %w", err) return From f8a5ab2526dc047cf0b4f4ab0dca2ba8778cef56 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 16 Jun 2022 14:59:59 +0300 Subject: [PATCH 026/220] update --- README.md | 2 + cmd/key-keeper/main.go | 5 +- go.mod | 1 + go.sum | 5 ++ internal/config/config.go | 8 +- internal/controller/ca.go | 34 +++----- internal/controller/controller.go | 21 +++-- internal/controller/csr.go | 10 +-- internal/controller/types.go | 11 --- internal/vault/store.go | 13 +++ internal/vault/type.go | 14 ++++ internal/vault/vault.go | 132 +++++++++++++++++++++++------- 12 files changed, 170 insertions(+), 86 deletions(-) create mode 100644 internal/vault/store.go create mode 100644 internal/vault/type.go diff --git a/README.md b/README.md index b4f0b23..d97f9c6 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ Example config.yml vault: address: "address vault" token: "unexpired token" + path_to_role_id: "path to local role id" + path_to_secret_id: "path to local secret id" timeout: "timeout request: 1s, 3m, 5h" certificates: root_path: "root ca path" diff --git a/cmd/key-keeper/main.go b/cmd/key-keeper/main.go index 6666409..09e1cd6 100644 --- a/cmd/key-keeper/main.go +++ b/cmd/key-keeper/main.go @@ -38,8 +38,7 @@ func main() { zap.L().Debug("configuration", zap.Any("config", cfg)) v, err := vault.New( - cfg.Vault.Address, - cfg.Vault.Token, + cfg.Vault, ) if err != nil { zap.L().Fatal("init vault", zap.Error(err)) @@ -47,7 +46,7 @@ func main() { cntl := controller.New( v, - cfg, + cfg.Certificates, ) go func() { diff --git a/go.mod b/go.mod index 223649d..62aade3 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.18 require ( github.com/hashicorp/vault/api v1.7.1 + github.com/hashicorp/vault/api/auth/approle v0.1.1 go.uber.org/zap v1.21.0 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b ) diff --git a/go.sum b/go.sum index 069b4b0..c3b8ef4 100644 --- a/go.sum +++ b/go.sum @@ -136,8 +136,12 @@ github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+l github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/vault/api v1.3.0/go.mod h1:EabNQLI0VWbWoGlA+oBLC8PXmR9D60aUVgQGvangFWQ= github.com/hashicorp/vault/api v1.7.1 h1:uUpxcZO3XV1Sb96dEtT+tZlSpV7U/zEi0NoksM7lU5M= github.com/hashicorp/vault/api v1.7.1/go.mod h1:TlKWwxZySuDARVFz/H0sf6rgWddIlX4t4DO9baT2nXc= +github.com/hashicorp/vault/api/auth/approle v0.1.1 h1:R5yA+xcNvw1ix6bDuWOaLOq2L4L77zDCVsethNw97xQ= +github.com/hashicorp/vault/api/auth/approle v0.1.1/go.mod h1:mHOLgh//xDx4dpqXoq6tS8Ob0FoCFWLU2ibJ26Lfmag= +github.com/hashicorp/vault/sdk v0.3.0/go.mod h1:aZ3fNuL5VNydQk8GcLJ2TV8YCRVvyaakYkhZRoVuhj0= github.com/hashicorp/vault/sdk v0.5.0 h1:EED7p0OCU3OY5SAqJwSANofY1YKMytm+jDHDQ2EzGVQ= github.com/hashicorp/vault/sdk v0.5.0/go.mod h1:UJZHlfwj7qUJG8g22CuxUgkdJouFrBNvBHCyx8XAPdo= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= @@ -178,6 +182,7 @@ github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdI github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= diff --git a/internal/config/config.go b/internal/config/config.go index faa9c6d..7f67e99 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -7,9 +7,15 @@ import ( "gopkg.in/yaml.v3" "github.com/terra-cube/key-keeper/internal/controller" + "github.com/terra-cube/key-keeper/internal/vault" ) -func Read(path string) (cfg controller.Config, err error) { +type Config struct { + Vault vault.Config `yaml:"vault"` + Certificates controller.Config `yaml:"certificates"` +} + +func Read(path string) (cfg Config, err error) { data, err := ioutil.ReadFile(path) if err != nil { err = fmt.Errorf("read config file %s: %w", path, err) diff --git a/internal/controller/ca.go b/internal/controller/ca.go index ed46309..dd2d643 100644 --- a/internal/controller/ca.go +++ b/internal/controller/ca.go @@ -1,7 +1,6 @@ package controller import ( - "context" "crypto/tls" "fmt" "time" @@ -10,14 +9,12 @@ import ( ) func (s *controller) CA(i CA) error { - ctx, cancel := context.WithTimeout(context.Background(), s.cfg.Vault.Timeout) - defer cancel() - storedICA, err := s.vault.Get(ctx, s.cfg.Certs.VaultKV, i.CommonName+"-ca") + storedICA, err := s.vault.Get(s.certs.VaultKV, i.CommonName+"-ca") if err != err { zap.L().Warn( "get intermediate ca", zap.String("name", i.CommonName+"-ca"), - zap.String("vault_kv", s.cfg.Certs.VaultKV), + zap.String("vault_kv", s.certs.VaultKV), zap.Error(err), ) } @@ -25,7 +22,7 @@ func (s *controller) CA(i CA) error { cert, key := []byte(storedICA["certificate"].(string)), []byte(storedICA["private_key"].(string)) var ca *tls.Certificate ca, err = parseToCert(cert, key) - if ca != nil && time.Until(ca.Leaf.NotAfter) < s.cfg.Certs.ValidInterval { + if ca != nil && time.Until(ca.Leaf.NotAfter) < s.certs.ValidInterval { zap.L().Warn( "expired intermediate-ca", zap.Float64("until_h", time.Until(ca.Leaf.NotAfter).Hours()), @@ -65,48 +62,39 @@ func (s *controller) CA(i CA) error { } func (s *controller) GenerateIntermediateCA(i CA) (crt, key []byte, err error) { // create intermediate CA - ctx, cancel := context.WithTimeout(context.Background(), s.cfg.Vault.Timeout) - defer cancel() - csrData := map[string]interface{}{ "common_name": fmt.Sprintf(intermediateCommonNameLayout, i.CommonName), "ttl": "8760h", } - path := s.cfg.Certs.CertPath + "/intermediate/generate/exported" - csr, err := s.vault.Write(ctx, path, csrData) + path := s.certs.CertPath + "/intermediate/generate/exported" + csr, err := s.vault.Write(path, csrData) if err != nil { err = fmt.Errorf("create intermediate CA: %w", err) return } // send the intermediate CA's CSR to the root CA for signing - ctx, cancel = context.WithTimeout(context.Background(), s.cfg.Vault.Timeout) - defer cancel() - icaData := map[string]interface{}{ "csr": csr["csr"], "format": "pem_bundle", "ttl": "8760h", } - path = s.cfg.Certs.RootPath + "/root/sign-intermediate" - ica, err := s.vault.Write(ctx, path, icaData) + path = s.certs.RootPath + "/root/sign-intermediate" + ica, err := s.vault.Write(path, icaData) if err != nil { err = fmt.Errorf("send the intermediate CA's CSR to the root CA for signing CA: %w", err) return } // publish the signed certificate back to the Intermediate CA - ctx, cancel = context.WithTimeout(context.Background(), s.cfg.Vault.Timeout) - defer cancel() - certData := map[string]interface{}{ "certificate": ica["certificate"], } - path = s.cfg.Certs.CertPath + "/intermediate/set-signed" - if _, err = s.vault.Write(ctx, path, certData); err != nil { + path = s.certs.CertPath + "/intermediate/set-signed" + if _, err = s.vault.Write(path, certData); err != nil { err = fmt.Errorf("publish the signed certificate back to the Intermediate CA: %w", err) return } @@ -115,14 +103,12 @@ func (s *controller) GenerateIntermediateCA(i CA) (crt, key []byte, err error) { } func (s *controller) StoreCA(i CA, crt, key []byte) error { - ctx, cancel := context.WithTimeout(context.Background(), s.cfg.Vault.Timeout) - defer cancel() // saving the created Intermediate CA storedICA := map[string]interface{}{ "certificate": string(crt), "private_key": string(key), } - if err := s.vault.Put(ctx, s.cfg.Certs.VaultKV, i.CommonName+"-ca", storedICA); err != nil { + if err := s.vault.Put(s.certs.VaultKV, i.CommonName+"-ca", storedICA); err != nil { return fmt.Errorf("saving in vault: %w", err) } diff --git a/internal/controller/controller.go b/internal/controller/controller.go index fa65057..509306a 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -1,31 +1,30 @@ package controller import ( - "context" "time" ) var intermediateCommonNameLayout = "%s Intermediate Authority" type vault interface { - Write(ctx context.Context, path string, data map[string]interface{}) (map[string]interface{}, error) - Read(ctx context.Context, path string) (map[string]interface{}, error) - List(ctx context.Context, path string) (map[string]interface{}, error) - Put(ctx context.Context, mountPath, secretePath string, data map[string]interface{}) error - Get(ctx context.Context, mountPath, secretePath string) (map[string]interface{}, error) + Write(path string, data map[string]interface{}) (map[string]interface{}, error) + Read(path string) (map[string]interface{}, error) + List(path string) (map[string]interface{}, error) + Put(mountPath, secretePath string, data map[string]interface{}) error + Get(mountPath, secretePath string) (map[string]interface{}, error) } type controller struct { vault vault - cfg Config + certs Config } -func New(store vault, cfg Config) *controller { +func New(store vault, certs Config) *controller { c := &controller{ vault: store, - cfg: cfg, + certs: certs, } return c } @@ -47,11 +46,11 @@ func (s *controller) TurnOn() error { } func (s *controller) Workflow() error { - if err := s.CA(s.cfg.Certs.CA); err != nil { + if err := s.CA(s.certs.CA); err != nil { return err } - for _, i := range s.cfg.Certs.CSR { + for _, i := range s.certs.CSR { if err := s.CSR(i); err != nil { return err } diff --git a/internal/controller/csr.go b/internal/controller/csr.go index c469486..9865e0c 100644 --- a/internal/controller/csr.go +++ b/internal/controller/csr.go @@ -1,7 +1,6 @@ package controller import ( - "context" "fmt" "os" "time" @@ -11,7 +10,7 @@ import ( func (s *controller) CSR(i CSR) error { csr, err := s.readCertificate(i.HostPath) - if csr != nil && time.Until(csr.Leaf.NotAfter) > s.cfg.Certs.ValidInterval { + if csr != nil && time.Until(csr.Leaf.NotAfter) > s.certs.ValidInterval { return nil } if err != nil && !os.IsNotExist(err) { @@ -35,14 +34,11 @@ func (s *controller) CSR(i CSR) error { } func (s *controller) GenerateCSR(i CSR) ([]byte, []byte, error) { - ctx, cancel := context.WithTimeout(context.Background(), s.cfg.Vault.Timeout) - defer cancel() - certData := map[string]interface{}{ "common_name": i.CommonName, } - path := s.cfg.Certs.CertPath + "/issue/" + i.Role - cert, err := s.vault.Write(ctx, path, certData) + path := s.certs.CertPath + "/issue/" + i.Role + cert, err := s.vault.Write(path, certData) if err != nil { return nil, nil, fmt.Errorf("generate with path %s : %w", path, err) } diff --git a/internal/controller/types.go b/internal/controller/types.go index e2587db..2fd9b95 100644 --- a/internal/controller/types.go +++ b/internal/controller/types.go @@ -5,17 +5,6 @@ import ( ) type Config struct { - Vault Vault `yaml:"vault"` - Certs Certificates `yaml:"certificates"` -} - -type Vault struct { - Address string `yaml:"address"` - Token string `yaml:"token"` - Timeout time.Duration `yaml:"timeout"` -} - -type Certificates struct { RootPath string `yaml:"root_path"` CertPath string `yaml:"cert_path"` VaultKV string `yaml:"vault_kv"` diff --git a/internal/vault/store.go b/internal/vault/store.go new file mode 100644 index 0000000..86217a5 --- /dev/null +++ b/internal/vault/store.go @@ -0,0 +1,13 @@ +package vault + +import ( + "os" +) + +func readFromFile(path string) ([]byte, error) { + return os.ReadFile(path) +} + +func writeToFile(path, date string) error { + return os.WriteFile(path, []byte(date), 0644) +} diff --git a/internal/vault/type.go b/internal/vault/type.go new file mode 100644 index 0000000..08c62ea --- /dev/null +++ b/internal/vault/type.go @@ -0,0 +1,14 @@ +package vault + +import ( + "time" +) + +type Config struct { + Address string `yaml:"address"` + Token string `yaml:"token"` + Role string `yaml:"role"` + PathToRoleID string `yaml:"path_to_role_id"` + PathToSecretID string `yaml:"path_to_secret_id"` + Timeout time.Duration `yaml:"timeout"` +} diff --git a/internal/vault/vault.go b/internal/vault/vault.go index d4b1596..ec6cb6b 100644 --- a/internal/vault/vault.go +++ b/internal/vault/vault.go @@ -2,67 +2,141 @@ package vault import ( "context" + "fmt" "net/http" - "time" "github.com/hashicorp/vault/api" + auth "github.com/hashicorp/vault/api/auth/approle" ) type vault struct { cli *api.Client + cfg Config } -func New(addr, token string) (*vault, error) { - httpClient := &http.Client{ - Timeout: 10 * time.Second, - } - +func New(cfg Config) (*vault, error) { client, err := api.NewClient( &api.Config{ - Address: addr, - HttpClient: httpClient, + Address: cfg.Address, + HttpClient: &http.Client{ + Timeout: cfg.Timeout, + }, }, ) - client.SetToken(token) + if err != nil { + return nil, fmt.Errorf("new vault client: %w", err) + } + client.SetToken(cfg.Token) - return &vault{ + s := &vault{ cli: client, - }, err + cfg: cfg, + } + + roleID, err := s.roleID() + if err != nil { + return nil, fmt.Errorf("get role id: %w", err) + } + secretID, err := s.secretID() + if err != nil { + return nil, fmt.Errorf("get secret id: %w", err) + } + + appRoleAuth, err := auth.NewAppRoleAuth( + roleID, + &auth.SecretID{ + FromString: secretID, + }, + ) + if err != nil { + return nil, err + } + + authInfo, err := client.Auth().Login(context.Background(), appRoleAuth) + if err != nil { + return nil, err + } + if authInfo == nil { + return nil, fmt.Errorf("no auth info was returned after login") + } + return s, nil +} + +func (s *vault) roleID() (string, error) { + path := fmt.Sprintf("auth/approle/role/%s/role-id", s.cfg.Role) + approle, err := s.Read(path) + if err != nil { + if roleID, rErr := readFromFile(s.cfg.PathToRoleID); rErr == nil { + return string(roleID), nil + } + return "", fmt.Errorf("read role_id fo role %s : %w", s.cfg.Role, err) + } + if approle == nil { + return "", fmt.Errorf("no role_id info was returned") + } + + roleID, ok := approle["role_id"] + if !ok { + return "", fmt.Errorf("not found role_id") + } + err = writeToFile(s.cfg.PathToRoleID, roleID.(string)) + return roleID.(string), err +} + +func (s *vault) secretID() (string, error) { + path := fmt.Sprintf("auth/approle/role/%s/secret-id", s.cfg.Role) + approle, err := s.Write(path, nil) + if err != nil { + if secretID, rErr := readFromFile(s.cfg.PathToSecretID); rErr == nil { + return string(secretID), nil + } + return "", fmt.Errorf("read secrete_id fo role %s : %w", s.cfg.Role, err) + } + if approle == nil { + return "", fmt.Errorf("no secrete_id info was returned") + } + + secretID, ok := approle["secret_id"] + if !ok { + return "", fmt.Errorf("not found secrete_id") + } + err = writeToFile(s.cfg.PathToRoleID, secretID.(string)) + return secretID.(string), err } -func (c *vault) List(ctx context.Context, path string) (map[string]interface{}, error) { - s, err := c.cli.Logical().ListWithContext(ctx, path) - if s != nil { - return s.Data, err +func (s *vault) List(path string) (map[string]interface{}, error) { + sec, err := s.cli.Logical().List(path) + if sec != nil { + return sec.Data, err } return nil, err } -func (c *vault) Read(ctx context.Context, path string) (map[string]interface{}, error) { - s, err := c.cli.Logical().ReadWithContext(ctx, path) - if s != nil { - return s.Data, err +func (s *vault) Read(path string) (map[string]interface{}, error) { + sec, err := s.cli.Logical().Read(path) + if sec != nil { + return sec.Data, err } return nil, err } -func (c *vault) Write(ctx context.Context, path string, data map[string]interface{}) (map[string]interface{}, error) { - s, err := c.cli.Logical().WriteWithContext(ctx, path, data) - if s != nil { - return s.Data, err +func (s *vault) Write(path string, data map[string]interface{}) (map[string]interface{}, error) { + sec, err := s.cli.Logical().Write(path, data) + if sec != nil { + return sec.Data, err } return nil, err } -func (c *vault) Put(ctx context.Context, mountPath, secretePath string, data map[string]interface{}) error { - _, err := c.cli.KVv2(mountPath).Put(ctx, secretePath, data) +func (s *vault) Put(mountPath, secretePath string, data map[string]interface{}) error { + _, err := s.cli.KVv2(mountPath).Put(context.Background(), secretePath, data) return err } -func (c *vault) Get(ctx context.Context, mountPath, secretePath string) (map[string]interface{}, error) { - s, err := c.cli.KVv2(mountPath).Get(ctx, secretePath) - if s != nil { - return s.Data, err +func (s *vault) Get(mountPath, secretePath string) (map[string]interface{}, error) { + sec, err := s.cli.KVv2(mountPath).Get(context.Background(), secretePath) + if sec != nil { + return sec.Data, err } return nil, err } From 0b98e85328bbfd079b40cdb0ae78f564937167a8 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 16 Jun 2022 17:07:22 +0300 Subject: [PATCH 027/220] update path --- internal/vault/vault.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/vault/vault.go b/internal/vault/vault.go index ec6cb6b..4c48ac3 100644 --- a/internal/vault/vault.go +++ b/internal/vault/vault.go @@ -63,7 +63,7 @@ func New(cfg Config) (*vault, error) { } func (s *vault) roleID() (string, error) { - path := fmt.Sprintf("auth/approle/role/%s/role-id", s.cfg.Role) + path := fmt.Sprintf("auth/%s/role-id", s.cfg.Role) approle, err := s.Read(path) if err != nil { if roleID, rErr := readFromFile(s.cfg.PathToRoleID); rErr == nil { @@ -84,7 +84,7 @@ func (s *vault) roleID() (string, error) { } func (s *vault) secretID() (string, error) { - path := fmt.Sprintf("auth/approle/role/%s/secret-id", s.cfg.Role) + path := fmt.Sprintf("auth/%s/secret-id", s.cfg.Role) approle, err := s.Write(path, nil) if err != nil { if secretID, rErr := readFromFile(s.cfg.PathToSecretID); rErr == nil { From d14c022d18d14acbe2d5d20b691f5864b6e10d79 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 16 Jun 2022 17:08:58 +0300 Subject: [PATCH 028/220] update readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d97f9c6..c131ffa 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ Example config.yml vault: address: "address vault" token: "unexpired token" + role: "role" path_to_role_id: "path to local role id" path_to_secret_id: "path to local secret id" timeout: "timeout request: 1s, 3m, 5h" From fa42283300d16c073f923a6448c49f57a4c0dc17 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 16 Jun 2022 17:26:49 +0300 Subject: [PATCH 029/220] update approle paths --- README.md | 3 ++- internal/vault/type.go | 3 ++- internal/vault/vault.go | 9 +++++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c131ffa..b0d165b 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,8 @@ Example config.yml vault: address: "address vault" token: "unexpired token" - role: "role" + role_path: "role-path" + role_name: "role-name" path_to_role_id: "path to local role id" path_to_secret_id: "path to local secret id" timeout: "timeout request: 1s, 3m, 5h" diff --git a/internal/vault/type.go b/internal/vault/type.go index 08c62ea..5233350 100644 --- a/internal/vault/type.go +++ b/internal/vault/type.go @@ -7,7 +7,8 @@ import ( type Config struct { Address string `yaml:"address"` Token string `yaml:"token"` - Role string `yaml:"role"` + RolePath string `yaml:"role_path"` + RoleName string `yaml:"role_name"` PathToRoleID string `yaml:"path_to_role_id"` PathToSecretID string `yaml:"path_to_secret_id"` Timeout time.Duration `yaml:"timeout"` diff --git a/internal/vault/vault.go b/internal/vault/vault.go index 4c48ac3..ea37721 100644 --- a/internal/vault/vault.go +++ b/internal/vault/vault.go @@ -47,6 +47,7 @@ func New(cfg Config) (*vault, error) { &auth.SecretID{ FromString: secretID, }, + auth.WithMountPath(fmt.Sprintf("auth/%s/login", cfg.RolePath)), ) if err != nil { return nil, err @@ -63,13 +64,13 @@ func New(cfg Config) (*vault, error) { } func (s *vault) roleID() (string, error) { - path := fmt.Sprintf("auth/%s/role-id", s.cfg.Role) + path := fmt.Sprintf("auth/%s/%s/role-id", s.cfg.RolePath, s.cfg.RoleName) approle, err := s.Read(path) if err != nil { if roleID, rErr := readFromFile(s.cfg.PathToRoleID); rErr == nil { return string(roleID), nil } - return "", fmt.Errorf("read role_id fo role %s : %w", s.cfg.Role, err) + return "", fmt.Errorf("read role_id fo role %s : %w", s.cfg.RoleName, err) } if approle == nil { return "", fmt.Errorf("no role_id info was returned") @@ -84,13 +85,13 @@ func (s *vault) roleID() (string, error) { } func (s *vault) secretID() (string, error) { - path := fmt.Sprintf("auth/%s/secret-id", s.cfg.Role) + path := fmt.Sprintf("auth/%s/%s/secret-id", s.cfg.RolePath, s.cfg.RoleName) approle, err := s.Write(path, nil) if err != nil { if secretID, rErr := readFromFile(s.cfg.PathToSecretID); rErr == nil { return string(secretID), nil } - return "", fmt.Errorf("read secrete_id fo role %s : %w", s.cfg.Role, err) + return "", fmt.Errorf("read secrete_id fo role %s : %w", s.cfg.RoleName, err) } if approle == nil { return "", fmt.Errorf("no secrete_id info was returned") From 6f180d99c572845e0aad69f49b2cfea6314482aa Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 16 Jun 2022 17:32:39 +0300 Subject: [PATCH 030/220] up --- internal/vault/vault.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/vault/vault.go b/internal/vault/vault.go index ea37721..5827712 100644 --- a/internal/vault/vault.go +++ b/internal/vault/vault.go @@ -64,7 +64,7 @@ func New(cfg Config) (*vault, error) { } func (s *vault) roleID() (string, error) { - path := fmt.Sprintf("auth/%s/%s/role-id", s.cfg.RolePath, s.cfg.RoleName) + path := fmt.Sprintf("auth/%s/role/%s/role-id", s.cfg.RolePath, s.cfg.RoleName) approle, err := s.Read(path) if err != nil { if roleID, rErr := readFromFile(s.cfg.PathToRoleID); rErr == nil { @@ -85,7 +85,7 @@ func (s *vault) roleID() (string, error) { } func (s *vault) secretID() (string, error) { - path := fmt.Sprintf("auth/%s/%s/secret-id", s.cfg.RolePath, s.cfg.RoleName) + path := fmt.Sprintf("auth/%s/role/%s/secret-id", s.cfg.RolePath, s.cfg.RoleName) approle, err := s.Write(path, nil) if err != nil { if secretID, rErr := readFromFile(s.cfg.PathToSecretID); rErr == nil { From 1ec26c6b450e1383e97814153f8470b058e1c489 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 16 Jun 2022 17:37:07 +0300 Subject: [PATCH 031/220] update --- internal/vault/vault.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/vault/vault.go b/internal/vault/vault.go index 5827712..6df8d23 100644 --- a/internal/vault/vault.go +++ b/internal/vault/vault.go @@ -64,13 +64,13 @@ func New(cfg Config) (*vault, error) { } func (s *vault) roleID() (string, error) { - path := fmt.Sprintf("auth/%s/role/%s/role-id", s.cfg.RolePath, s.cfg.RoleName) + path := fmt.Sprintf("auth/%s/approle/role/%s/role-id", s.cfg.RolePath, s.cfg.RoleName) approle, err := s.Read(path) if err != nil { if roleID, rErr := readFromFile(s.cfg.PathToRoleID); rErr == nil { return string(roleID), nil } - return "", fmt.Errorf("read role_id fo role %s : %w", s.cfg.RoleName, err) + return "", fmt.Errorf("read role_id for path: %s : %w", path, err) } if approle == nil { return "", fmt.Errorf("no role_id info was returned") @@ -85,13 +85,13 @@ func (s *vault) roleID() (string, error) { } func (s *vault) secretID() (string, error) { - path := fmt.Sprintf("auth/%s/role/%s/secret-id", s.cfg.RolePath, s.cfg.RoleName) + path := fmt.Sprintf("auth/%s/approle/role/%s/secret-id", s.cfg.RolePath, s.cfg.RoleName) approle, err := s.Write(path, nil) if err != nil { if secretID, rErr := readFromFile(s.cfg.PathToSecretID); rErr == nil { return string(secretID), nil } - return "", fmt.Errorf("read secrete_id fo role %s : %w", s.cfg.RoleName, err) + return "", fmt.Errorf("read secrete_id for path: %s : %w", path, err) } if approle == nil { return "", fmt.Errorf("no secrete_id info was returned") From 6f9846fa74e9cc3676c8d46264a83d1f0196a6ab Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 16 Jun 2022 17:40:31 +0300 Subject: [PATCH 032/220] update --- internal/vault/vault.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/vault/vault.go b/internal/vault/vault.go index 6df8d23..0e4e9f2 100644 --- a/internal/vault/vault.go +++ b/internal/vault/vault.go @@ -47,7 +47,7 @@ func New(cfg Config) (*vault, error) { &auth.SecretID{ FromString: secretID, }, - auth.WithMountPath(fmt.Sprintf("auth/%s/login", cfg.RolePath)), + auth.WithMountPath(cfg.RolePath), ) if err != nil { return nil, err From 60d5d2cad9a703be3cd0c56125e33cf956bbf6e0 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 16 Jun 2022 17:46:12 +0300 Subject: [PATCH 033/220] update --- internal/vault/vault.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/vault/vault.go b/internal/vault/vault.go index 0e4e9f2..c7a4fd5 100644 --- a/internal/vault/vault.go +++ b/internal/vault/vault.go @@ -64,7 +64,7 @@ func New(cfg Config) (*vault, error) { } func (s *vault) roleID() (string, error) { - path := fmt.Sprintf("auth/%s/approle/role/%s/role-id", s.cfg.RolePath, s.cfg.RoleName) + path := fmt.Sprintf("auth/%s/role/%s/role-id", s.cfg.RolePath, s.cfg.RoleName) approle, err := s.Read(path) if err != nil { if roleID, rErr := readFromFile(s.cfg.PathToRoleID); rErr == nil { @@ -85,7 +85,7 @@ func (s *vault) roleID() (string, error) { } func (s *vault) secretID() (string, error) { - path := fmt.Sprintf("auth/%s/approle/role/%s/secret-id", s.cfg.RolePath, s.cfg.RoleName) + path := fmt.Sprintf("auth/%s/role/%s/secret-id", s.cfg.RolePath, s.cfg.RoleName) approle, err := s.Write(path, nil) if err != nil { if secretID, rErr := readFromFile(s.cfg.PathToSecretID); rErr == nil { From d7ddadfaeb97b767e5c7dcd65562982f534436d5 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 16 Jun 2022 17:48:52 +0300 Subject: [PATCH 034/220] update --- internal/vault/vault.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/vault/vault.go b/internal/vault/vault.go index c7a4fd5..5ddee86 100644 --- a/internal/vault/vault.go +++ b/internal/vault/vault.go @@ -101,7 +101,7 @@ func (s *vault) secretID() (string, error) { if !ok { return "", fmt.Errorf("not found secrete_id") } - err = writeToFile(s.cfg.PathToRoleID, secretID.(string)) + err = writeToFile(s.cfg.PathToSecretID, secretID.(string)) return secretID.(string), err } From 387e2bc26e523e276e38e2c75b2f8fcb27018a84 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Fri, 17 Jun 2022 13:23:02 +0300 Subject: [PATCH 035/220] add ips add hosts --- README.md | 6 ++++++ internal/controller/csr.go | 2 ++ internal/controller/types.go | 8 +++++--- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b0d165b..3a191bb 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,12 @@ certificates: - common_name: "common_name" role: "role for generate cert" host_path: "path for store of ca in host" + hosts: + - "host1" + "host2" + ips: + - "127.127.0.7" + "127.127.0.9" ``` Build: diff --git a/internal/controller/csr.go b/internal/controller/csr.go index 9865e0c..1b599d5 100644 --- a/internal/controller/csr.go +++ b/internal/controller/csr.go @@ -36,6 +36,8 @@ func (s *controller) CSR(i CSR) error { func (s *controller) GenerateCSR(i CSR) ([]byte, []byte, error) { certData := map[string]interface{}{ "common_name": i.CommonName, + "alt_names": i.Hosts, + "ip_sans": i.IPs, } path := s.certs.CertPath + "/issue/" + i.Role cert, err := s.vault.Write(path, certData) diff --git a/internal/controller/types.go b/internal/controller/types.go index 2fd9b95..5997d3b 100644 --- a/internal/controller/types.go +++ b/internal/controller/types.go @@ -19,7 +19,9 @@ type CA struct { } type CSR struct { - CommonName string `yaml:"common_name"` - Role string `yaml:"role"` - HostPath string `yaml:"host_path"` + CommonName string `yaml:"common_name"` + Hosts []string `yaml:"hosts"` + IPs []string `yaml:"ips"` + Role string `yaml:"role"` + HostPath string `yaml:"host_path"` } From c462c7b67ad514cd527b4f092e588ca50ff5006a Mon Sep 17 00:00:00 2001 From: irbgeo Date: Fri, 17 Jun 2022 13:26:36 +0300 Subject: [PATCH 036/220] up readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3a191bb..c6eec35 100644 --- a/README.md +++ b/README.md @@ -25,10 +25,10 @@ certificates: host_path: "path for store of ca in host" hosts: - "host1" - "host2" + - "host2" ips: - "127.127.0.7" - "127.127.0.9" + - "127.127.0.9" ``` Build: From 6ffec41eee46ec2a460b0c024c100d4178b94d98 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Fri, 17 Jun 2022 13:29:29 +0300 Subject: [PATCH 037/220] up --- internal/controller/csr.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/controller/csr.go b/internal/controller/csr.go index 1b599d5..3e609ca 100644 --- a/internal/controller/csr.go +++ b/internal/controller/csr.go @@ -3,6 +3,7 @@ package controller import ( "fmt" "os" + "strings" "time" "go.uber.org/zap" @@ -36,8 +37,8 @@ func (s *controller) CSR(i CSR) error { func (s *controller) GenerateCSR(i CSR) ([]byte, []byte, error) { certData := map[string]interface{}{ "common_name": i.CommonName, - "alt_names": i.Hosts, - "ip_sans": i.IPs, + "alt_names": strings.Join(i.Hosts, ","), + "ip_sans": strings.Join(i.IPs, ","), } path := s.certs.CertPath + "/issue/" + i.Role cert, err := s.vault.Write(path, certData) From 4f7ae920b8e8a14fbe8e6dc2f98b4d4729f2c3bd Mon Sep 17 00:00:00 2001 From: irbgeo Date: Fri, 17 Jun 2022 14:18:44 +0300 Subject: [PATCH 038/220] update readme --- README.md | 28 +++++++++++++++------------- internal/controller/ca.go | 8 ++++---- internal/controller/controller.go | 10 ++++++---- internal/controller/csr.go | 4 ++-- internal/controller/types.go | 13 +++++++------ internal/vault/type.go | 14 +++++++------- internal/vault/vault.go | 18 +++++++++--------- 7 files changed, 50 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index c6eec35..2304f96 100644 --- a/README.md +++ b/README.md @@ -5,30 +5,32 @@ Example config.yml ```yaml vault: address: "address vault" - token: "unexpired token" - role_path: "role-path" - role_name: "role-name" - path_to_role_id: "path to local role id" - path_to_secret_id: "path to local secret id" - timeout: "timeout request: 1s, 3m, 5h" + bootstrap_token: "unexpired token" + approle_path: "role-path" + approle_name: "role-name" + local_path_to_role_id: "path to local role id" + local_path_to_secret_id: "path to local secret id" + request_timeout: "timeout request: 1s, 3m, 5h" certificates: - root_path: "root ca path" - cert_path: "path for generate certificate" vault_kv: "path for kv" - valid_interval: "valid expire cert interval: 1s, 3m, 5h" + reissue_interval: "interval for initialization reissue certificate: 1s, 3m, 5h" ca: - common_name: "common_name" - host_path: "path for store of ca in host" - csr: - common_name: "common_name" - role: "role for generate cert" + root_path_ca: "root ca path" + cert_path: "path for generate certificate" host_path: "path for store of ca in host" + csr: + - common_name: "common_name" hosts: - "host1" - "host2" ips: - "127.127.0.7" - "127.127.0.9" + root_path_ca: "root ca path" + cert_path: "path for generate certificate" + role: "role for generate cert" + host_path: "path for store of ca in host" ``` Build: diff --git a/internal/controller/ca.go b/internal/controller/ca.go index dd2d643..aab0180 100644 --- a/internal/controller/ca.go +++ b/internal/controller/ca.go @@ -22,7 +22,7 @@ func (s *controller) CA(i CA) error { cert, key := []byte(storedICA["certificate"].(string)), []byte(storedICA["private_key"].(string)) var ca *tls.Certificate ca, err = parseToCert(cert, key) - if ca != nil && time.Until(ca.Leaf.NotAfter) < s.certs.ValidInterval { + if ca != nil && time.Until(ca.Leaf.NotAfter) < s.certs.ReissueInterval { zap.L().Warn( "expired intermediate-ca", zap.Float64("until_h", time.Until(ca.Leaf.NotAfter).Hours()), @@ -67,7 +67,7 @@ func (s *controller) GenerateIntermediateCA(i CA) (crt, key []byte, err error) { "ttl": "8760h", } - path := s.certs.CertPath + "/intermediate/generate/exported" + path := i.CertPath + "/intermediate/generate/exported" csr, err := s.vault.Write(path, csrData) if err != nil { err = fmt.Errorf("create intermediate CA: %w", err) @@ -81,7 +81,7 @@ func (s *controller) GenerateIntermediateCA(i CA) (crt, key []byte, err error) { "ttl": "8760h", } - path = s.certs.RootPath + "/root/sign-intermediate" + path = i.RootPathCA + "/root/sign-intermediate" ica, err := s.vault.Write(path, icaData) if err != nil { err = fmt.Errorf("send the intermediate CA's CSR to the root CA for signing CA: %w", err) @@ -93,7 +93,7 @@ func (s *controller) GenerateIntermediateCA(i CA) (crt, key []byte, err error) { "certificate": ica["certificate"], } - path = s.certs.CertPath + "/intermediate/set-signed" + path = i.CertPath + "/intermediate/set-signed" if _, err = s.vault.Write(path, certData); err != nil { err = fmt.Errorf("publish the signed certificate back to the Intermediate CA: %w", err) return diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 509306a..b1422d6 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -46,12 +46,14 @@ func (s *controller) TurnOn() error { } func (s *controller) Workflow() error { - if err := s.CA(s.certs.CA); err != nil { - return err + for _, c := range s.certs.CA { + if err := s.CA(c); err != nil { + return err + } } - for _, i := range s.certs.CSR { - if err := s.CSR(i); err != nil { + for _, c := range s.certs.CSR { + if err := s.CSR(c); err != nil { return err } } diff --git a/internal/controller/csr.go b/internal/controller/csr.go index 3e609ca..a765dcf 100644 --- a/internal/controller/csr.go +++ b/internal/controller/csr.go @@ -11,7 +11,7 @@ import ( func (s *controller) CSR(i CSR) error { csr, err := s.readCertificate(i.HostPath) - if csr != nil && time.Until(csr.Leaf.NotAfter) > s.certs.ValidInterval { + if csr != nil && time.Until(csr.Leaf.NotAfter) > s.certs.ReissueInterval { return nil } if err != nil && !os.IsNotExist(err) { @@ -40,7 +40,7 @@ func (s *controller) GenerateCSR(i CSR) ([]byte, []byte, error) { "alt_names": strings.Join(i.Hosts, ","), "ip_sans": strings.Join(i.IPs, ","), } - path := s.certs.CertPath + "/issue/" + i.Role + path := i.CertPath + "/issue/" + i.Role cert, err := s.vault.Write(path, certData) if err != nil { return nil, nil, fmt.Errorf("generate with path %s : %w", path, err) diff --git a/internal/controller/types.go b/internal/controller/types.go index 5997d3b..b2ccbad 100644 --- a/internal/controller/types.go +++ b/internal/controller/types.go @@ -5,16 +5,16 @@ import ( ) type Config struct { - RootPath string `yaml:"root_path"` - CertPath string `yaml:"cert_path"` - VaultKV string `yaml:"vault_kv"` - ValidInterval time.Duration `yaml:"valid_interval"` - CA CA `yaml:"ca,omitempty"` - CSR []CSR `yaml:"csr,omitempty"` + VaultKV string `yaml:"vault_kv"` + ReissueInterval time.Duration `yaml:"reissue_interval"` + CA []CA `yaml:"ca,omitempty"` + CSR []CSR `yaml:"csr,omitempty"` } type CA struct { CommonName string `yaml:"common_name"` + RootPathCA string `yaml:"root_path_ca"` + CertPath string `yaml:"cert_path"` HostPath string `yaml:"host_path"` } @@ -22,6 +22,7 @@ type CSR struct { CommonName string `yaml:"common_name"` Hosts []string `yaml:"hosts"` IPs []string `yaml:"ips"` + CertPath string `yaml:"cert_path"` Role string `yaml:"role"` HostPath string `yaml:"host_path"` } diff --git a/internal/vault/type.go b/internal/vault/type.go index 5233350..71baccc 100644 --- a/internal/vault/type.go +++ b/internal/vault/type.go @@ -5,11 +5,11 @@ import ( ) type Config struct { - Address string `yaml:"address"` - Token string `yaml:"token"` - RolePath string `yaml:"role_path"` - RoleName string `yaml:"role_name"` - PathToRoleID string `yaml:"path_to_role_id"` - PathToSecretID string `yaml:"path_to_secret_id"` - Timeout time.Duration `yaml:"timeout"` + Address string `yaml:"address"` + BootsrapToken string `yaml:"bootstrap_token"` + AppRolePath string `yaml:"approle_path"` + AppRoleName string `yaml:"approle_name"` + LocalPathToRoleID string `yaml:"local_path_to_role_id"` + LocalPathToSecretID string `yaml:"local_path_to_secret_id"` + RequestTimeout time.Duration `yaml:"request_timeout"` } diff --git a/internal/vault/vault.go b/internal/vault/vault.go index 5ddee86..191cf28 100644 --- a/internal/vault/vault.go +++ b/internal/vault/vault.go @@ -19,14 +19,14 @@ func New(cfg Config) (*vault, error) { &api.Config{ Address: cfg.Address, HttpClient: &http.Client{ - Timeout: cfg.Timeout, + Timeout: cfg.RequestTimeout, }, }, ) if err != nil { return nil, fmt.Errorf("new vault client: %w", err) } - client.SetToken(cfg.Token) + client.SetToken(cfg.BootsrapToken) s := &vault{ cli: client, @@ -47,7 +47,7 @@ func New(cfg Config) (*vault, error) { &auth.SecretID{ FromString: secretID, }, - auth.WithMountPath(cfg.RolePath), + auth.WithMountPath(cfg.AppRolePath), ) if err != nil { return nil, err @@ -64,10 +64,10 @@ func New(cfg Config) (*vault, error) { } func (s *vault) roleID() (string, error) { - path := fmt.Sprintf("auth/%s/role/%s/role-id", s.cfg.RolePath, s.cfg.RoleName) + path := fmt.Sprintf("auth/%s/role/%s/role-id", s.cfg.AppRolePath, s.cfg.AppRoleName) approle, err := s.Read(path) if err != nil { - if roleID, rErr := readFromFile(s.cfg.PathToRoleID); rErr == nil { + if roleID, rErr := readFromFile(s.cfg.LocalPathToRoleID); rErr == nil { return string(roleID), nil } return "", fmt.Errorf("read role_id for path: %s : %w", path, err) @@ -80,15 +80,15 @@ func (s *vault) roleID() (string, error) { if !ok { return "", fmt.Errorf("not found role_id") } - err = writeToFile(s.cfg.PathToRoleID, roleID.(string)) + err = writeToFile(s.cfg.LocalPathToRoleID, roleID.(string)) return roleID.(string), err } func (s *vault) secretID() (string, error) { - path := fmt.Sprintf("auth/%s/role/%s/secret-id", s.cfg.RolePath, s.cfg.RoleName) + path := fmt.Sprintf("auth/%s/role/%s/secret-id", s.cfg.AppRolePath, s.cfg.AppRoleName) approle, err := s.Write(path, nil) if err != nil { - if secretID, rErr := readFromFile(s.cfg.PathToSecretID); rErr == nil { + if secretID, rErr := readFromFile(s.cfg.LocalPathToSecretID); rErr == nil { return string(secretID), nil } return "", fmt.Errorf("read secrete_id for path: %s : %w", path, err) @@ -101,7 +101,7 @@ func (s *vault) secretID() (string, error) { if !ok { return "", fmt.Errorf("not found secrete_id") } - err = writeToFile(s.cfg.PathToSecretID, secretID.(string)) + err = writeToFile(s.cfg.LocalPathToSecretID, secretID.(string)) return secretID.(string), err } From 5cc09ecdd7b77eedde65a01d7eda808ebe4ef9ec Mon Sep 17 00:00:00 2001 From: irbgeo Date: Fri, 17 Jun 2022 14:36:58 +0300 Subject: [PATCH 039/220] update err info --- internal/vault/vault.go | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/internal/vault/vault.go b/internal/vault/vault.go index 191cf28..0d52ec4 100644 --- a/internal/vault/vault.go +++ b/internal/vault/vault.go @@ -11,7 +11,6 @@ import ( type vault struct { cli *api.Client - cfg Config } func New(cfg Config) (*vault, error) { @@ -30,14 +29,13 @@ func New(cfg Config) (*vault, error) { s := &vault{ cli: client, - cfg: cfg, } - roleID, err := s.roleID() + roleID, err := s.roleID(cfg) if err != nil { return nil, fmt.Errorf("get role id: %w", err) } - secretID, err := s.secretID() + secretID, err := s.secretID(cfg) if err != nil { return nil, fmt.Errorf("get secret id: %w", err) } @@ -63,11 +61,11 @@ func New(cfg Config) (*vault, error) { return s, nil } -func (s *vault) roleID() (string, error) { - path := fmt.Sprintf("auth/%s/role/%s/role-id", s.cfg.AppRolePath, s.cfg.AppRoleName) +func (s *vault) roleID(cfg Config) (string, error) { + path := fmt.Sprintf("auth/%s/role/%s/role-id", cfg.AppRolePath, cfg.AppRoleName) approle, err := s.Read(path) if err != nil { - if roleID, rErr := readFromFile(s.cfg.LocalPathToRoleID); rErr == nil { + if roleID, rErr := readFromFile(cfg.LocalPathToRoleID); rErr == nil { return string(roleID), nil } return "", fmt.Errorf("read role_id for path: %s : %w", path, err) @@ -80,15 +78,17 @@ func (s *vault) roleID() (string, error) { if !ok { return "", fmt.Errorf("not found role_id") } - err = writeToFile(s.cfg.LocalPathToRoleID, roleID.(string)) + if err = writeToFile(cfg.LocalPathToRoleID, roleID.(string)); err != nil { + return "", fmt.Errorf("save role id path: %s id: %w", cfg.LocalPathToRoleID, err) + } return roleID.(string), err } -func (s *vault) secretID() (string, error) { - path := fmt.Sprintf("auth/%s/role/%s/secret-id", s.cfg.AppRolePath, s.cfg.AppRoleName) +func (s *vault) secretID(cfg Config) (string, error) { + path := fmt.Sprintf("auth/%s/role/%s/secret-id", cfg.AppRolePath, cfg.AppRoleName) approle, err := s.Write(path, nil) if err != nil { - if secretID, rErr := readFromFile(s.cfg.LocalPathToSecretID); rErr == nil { + if secretID, rErr := readFromFile(cfg.LocalPathToSecretID); rErr == nil { return string(secretID), nil } return "", fmt.Errorf("read secrete_id for path: %s : %w", path, err) @@ -101,7 +101,10 @@ func (s *vault) secretID() (string, error) { if !ok { return "", fmt.Errorf("not found secrete_id") } - err = writeToFile(s.cfg.LocalPathToSecretID, secretID.(string)) + + if err = writeToFile(cfg.LocalPathToSecretID, secretID.(string)); err != nil { + return "", fmt.Errorf("save secret id path: %s id: %w", cfg.LocalPathToSecretID, err) + } return secretID.(string), err } From 7d0e25682de93997830d19bf857a01f2e1f1d6f1 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Fri, 17 Jun 2022 14:47:49 +0300 Subject: [PATCH 040/220] add comments --- cmd/key-keeper/main.go | 2 +- internal/config/config.go | 1 + internal/controller/ca.go | 11 ++++++----- internal/controller/controller.go | 15 +++++++-------- internal/controller/csr.go | 10 +++++----- internal/vault/type.go | 1 + internal/vault/vault.go | 12 ++++-------- 7 files changed, 25 insertions(+), 27 deletions(-) diff --git a/cmd/key-keeper/main.go b/cmd/key-keeper/main.go index 09e1cd6..13a9aad 100644 --- a/cmd/key-keeper/main.go +++ b/cmd/key-keeper/main.go @@ -50,7 +50,7 @@ func main() { ) go func() { - if err := cntl.TurnOn(); err != nil { + if err := cntl.Start(); err != nil { zap.L().Fatal("start", zap.Error(err)) } }() diff --git a/internal/config/config.go b/internal/config/config.go index 7f67e99..ec6a5cb 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -15,6 +15,7 @@ type Config struct { Certificates controller.Config `yaml:"certificates"` } +// Read config by path. func Read(path string) (cfg Config, err error) { data, err := ioutil.ReadFile(path) if err != nil { diff --git a/internal/controller/ca.go b/internal/controller/ca.go index aab0180..9ca5506 100644 --- a/internal/controller/ca.go +++ b/internal/controller/ca.go @@ -8,7 +8,7 @@ import ( "go.uber.org/zap" ) -func (s *controller) CA(i CA) error { +func (s *controller) ca(i CA) error { storedICA, err := s.vault.Get(s.certs.VaultKV, i.CommonName+"-ca") if err != err { zap.L().Warn( @@ -41,7 +41,7 @@ func (s *controller) CA(i CA) error { } } - cert, key, err := s.GenerateIntermediateCA(i) + cert, key, err := s.generateIntermediateCA(i) if err != nil { zap.L().Error( "generate intermediate-ca", @@ -50,7 +50,7 @@ func (s *controller) CA(i CA) error { return err } - if err = s.StoreCA(i, cert, key); err != nil { + if err = s.storeCA(i, cert, key); err != nil { zap.L().Error( "stored intermediate-ca", zap.Error(err), @@ -60,7 +60,8 @@ func (s *controller) CA(i CA) error { return nil } -func (s *controller) GenerateIntermediateCA(i CA) (crt, key []byte, err error) { + +func (s *controller) generateIntermediateCA(i CA) (crt, key []byte, err error) { // create intermediate CA csrData := map[string]interface{}{ "common_name": fmt.Sprintf(intermediateCommonNameLayout, i.CommonName), @@ -102,7 +103,7 @@ func (s *controller) GenerateIntermediateCA(i CA) (crt, key []byte, err error) { return []byte(ica["certificate"].(string)), []byte(csr["private_key"].(string)), nil } -func (s *controller) StoreCA(i CA, crt, key []byte) error { +func (s *controller) storeCA(i CA, crt, key []byte) error { // saving the created Intermediate CA storedICA := map[string]interface{}{ "certificate": string(crt), diff --git a/internal/controller/controller.go b/internal/controller/controller.go index b1422d6..17c9298 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -9,7 +9,6 @@ var intermediateCommonNameLayout = "%s Intermediate Authority" type vault interface { Write(path string, data map[string]interface{}) (map[string]interface{}, error) Read(path string) (map[string]interface{}, error) - List(path string) (map[string]interface{}, error) Put(mountPath, secretePath string, data map[string]interface{}) error Get(mountPath, secretePath string) (map[string]interface{}, error) } @@ -23,21 +22,21 @@ type controller struct { func New(store vault, certs Config) *controller { c := &controller{ vault: store, - certs: certs, } return c } -func (s *controller) TurnOn() error { - if err := s.Workflow(); err != nil { +// Start controller of key-keeper. +func (s *controller) Start() error { + if err := s.workflow(); err != nil { return err } t := time.NewTicker(time.Hour) defer t.Stop() for range t.C { - if err := s.Workflow(); err != nil { + if err := s.workflow(); err != nil { return err } } @@ -45,15 +44,15 @@ func (s *controller) TurnOn() error { return nil } -func (s *controller) Workflow() error { +func (s *controller) workflow() error { for _, c := range s.certs.CA { - if err := s.CA(c); err != nil { + if err := s.ca(c); err != nil { return err } } for _, c := range s.certs.CSR { - if err := s.CSR(c); err != nil { + if err := s.csr(c); err != nil { return err } } diff --git a/internal/controller/csr.go b/internal/controller/csr.go index a765dcf..0e6c963 100644 --- a/internal/controller/csr.go +++ b/internal/controller/csr.go @@ -9,7 +9,7 @@ import ( "go.uber.org/zap" ) -func (s *controller) CSR(i CSR) error { +func (s *controller) csr(i CSR) error { csr, err := s.readCertificate(i.HostPath) if csr != nil && time.Until(csr.Leaf.NotAfter) > s.certs.ReissueInterval { return nil @@ -19,13 +19,13 @@ func (s *controller) CSR(i CSR) error { return err } - cert, key, err := s.GenerateCSR(i) + cert, key, err := s.generateCSR(i) if err != nil { zap.L().Error("generate csr", zap.Error(err)) return err } - err = s.StoreCSR(i, cert, key) + err = s.storeCSR(i, cert, key) if err != nil { zap.L().Error("store csr", zap.Error(err)) return err @@ -34,7 +34,7 @@ func (s *controller) CSR(i CSR) error { return err } -func (s *controller) GenerateCSR(i CSR) ([]byte, []byte, error) { +func (s *controller) generateCSR(i CSR) ([]byte, []byte, error) { certData := map[string]interface{}{ "common_name": i.CommonName, "alt_names": strings.Join(i.Hosts, ","), @@ -48,7 +48,7 @@ func (s *controller) GenerateCSR(i CSR) ([]byte, []byte, error) { return []byte(cert["certificate"].(string)), []byte(cert["private_key"].(string)), nil } -func (s *controller) StoreCSR(i CSR, cert, key []byte) error { +func (s *controller) storeCSR(i CSR, cert, key []byte) error { if err := s.storeCertificate(i.HostPath, cert, key); err != nil { return fmt.Errorf("host path %s : %w", i.HostPath, err) } diff --git a/internal/vault/type.go b/internal/vault/type.go index 71baccc..77185c6 100644 --- a/internal/vault/type.go +++ b/internal/vault/type.go @@ -4,6 +4,7 @@ import ( "time" ) +// Config for work with vault type Config struct { Address string `yaml:"address"` BootsrapToken string `yaml:"bootstrap_token"` diff --git a/internal/vault/vault.go b/internal/vault/vault.go index 0d52ec4..511a319 100644 --- a/internal/vault/vault.go +++ b/internal/vault/vault.go @@ -108,14 +108,7 @@ func (s *vault) secretID(cfg Config) (string, error) { return secretID.(string), err } -func (s *vault) List(path string) (map[string]interface{}, error) { - sec, err := s.cli.Logical().List(path) - if sec != nil { - return sec.Data, err - } - return nil, err -} - +// Read secret from vault by path. func (s *vault) Read(path string) (map[string]interface{}, error) { sec, err := s.cli.Logical().Read(path) if sec != nil { @@ -124,6 +117,7 @@ func (s *vault) Read(path string) (map[string]interface{}, error) { return nil, err } +// Write secret in vault by path. func (s *vault) Write(path string, data map[string]interface{}) (map[string]interface{}, error) { sec, err := s.cli.Logical().Write(path, data) if sec != nil { @@ -132,11 +126,13 @@ func (s *vault) Write(path string, data map[string]interface{}) (map[string]inte return nil, err } +// Put in KV. func (s *vault) Put(mountPath, secretePath string, data map[string]interface{}) error { _, err := s.cli.KVv2(mountPath).Put(context.Background(), secretePath, data) return err } +// Get from KV. func (s *vault) Get(mountPath, secretePath string) (map[string]interface{}, error) { sec, err := s.cli.KVv2(mountPath).Get(context.Background(), secretePath) if sec != nil { From 513b76ee379033abb0206b830bb3c7e90def07ce Mon Sep 17 00:00:00 2001 From: irbgeo Date: Fri, 17 Jun 2022 20:58:11 +0300 Subject: [PATCH 041/220] update --- internal/controller/ca.go | 1 + internal/controller/controller.go | 29 +++++++++++++++-------------- internal/controller/csr.go | 2 ++ 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/internal/controller/ca.go b/internal/controller/ca.go index 9ca5506..349b8ac 100644 --- a/internal/controller/ca.go +++ b/internal/controller/ca.go @@ -100,6 +100,7 @@ func (s *controller) generateIntermediateCA(i CA) (crt, key []byte, err error) { return } + zap.L().Info("ca generated", zap.String("common_name", i.CommonName)) return []byte(ica["certificate"].(string)), []byte(csr["private_key"].(string)), nil } diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 17c9298..cfe42ad 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -2,6 +2,8 @@ package controller import ( "time" + + "go.uber.org/zap" ) var intermediateCommonNameLayout = "%s Intermediate Authority" @@ -29,32 +31,31 @@ func New(store vault, certs Config) *controller { // Start controller of key-keeper. func (s *controller) Start() error { - if err := s.workflow(); err != nil { - return err - } + s.workflow() t := time.NewTicker(time.Hour) defer t.Stop() for range t.C { - if err := s.workflow(); err != nil { - return err - } + s.workflow() } return nil } -func (s *controller) workflow() error { +func (s *controller) workflow() { for _, c := range s.certs.CA { - if err := s.ca(c); err != nil { - return err - } + go func(c CA) { + if err := s.ca(c); err != nil { + zap.L().Error("ca", zap.String("common_name", c.CommonName), zap.Error(err)) + } + }(c) } for _, c := range s.certs.CSR { - if err := s.csr(c); err != nil { - return err - } + go func(c CSR) { + if err := s.csr(c); err != nil { + zap.L().Error("ca", zap.String("common_name", c.CommonName), zap.Error(err)) + } + }(c) } - return nil } diff --git a/internal/controller/csr.go b/internal/controller/csr.go index 0e6c963..a2e8b67 100644 --- a/internal/controller/csr.go +++ b/internal/controller/csr.go @@ -45,6 +45,8 @@ func (s *controller) generateCSR(i CSR) ([]byte, []byte, error) { if err != nil { return nil, nil, fmt.Errorf("generate with path %s : %w", path, err) } + + zap.L().Info("csr generated", zap.String("common_name", i.CommonName)) return []byte(cert["certificate"].(string)), []byte(cert["private_key"].(string)), nil } From 90ae286885ab4c4ad0be6b46baba3dbb25bac9de Mon Sep 17 00:00:00 2001 From: irbgeo Date: Sat, 18 Jun 2022 20:51:42 +0300 Subject: [PATCH 042/220] order of work with certs --- internal/controller/controller.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/internal/controller/controller.go b/internal/controller/controller.go index cfe42ad..95b21d7 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -1,6 +1,7 @@ package controller import ( + "sync" "time" "go.uber.org/zap" @@ -43,13 +44,17 @@ func (s *controller) Start() error { } func (s *controller) workflow() { + wg := &sync.WaitGroup{} for _, c := range s.certs.CA { + wg.Add(1) go func(c CA) { + defer wg.Done() if err := s.ca(c); err != nil { zap.L().Error("ca", zap.String("common_name", c.CommonName), zap.Error(err)) } }(c) } + wg.Wait() for _, c := range s.certs.CSR { go func(c CSR) { From ac7d778d2b67a2355d80ea0f0da3d91b4a8f524f Mon Sep 17 00:00:00 2001 From: irbgeo Date: Sat, 18 Jun 2022 21:16:46 +0300 Subject: [PATCH 043/220] add root ca --- README.md | 3 ++ internal/controller/controller.go | 23 ++++++++------ internal/controller/csr.go | 12 ++----- .../controller/{ca.go => intermediate-ca.go} | 14 +++------ internal/controller/root-ca.go | 31 +++++++++++++++++++ internal/controller/types.go | 16 +++++++--- 6 files changed, 66 insertions(+), 33 deletions(-) rename internal/controller/{ca.go => intermediate-ca.go} (90%) create mode 100644 internal/controller/root-ca.go diff --git a/README.md b/README.md index 2304f96..96c9dd1 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,9 @@ certificates: vault_kv: "path for kv" reissue_interval: "interval for initialization reissue certificate: 1s, 3m, 5h" ca: + - common_name: "common_name" + root_path_ca: "root ca path" + intermediate_ca: - common_name: "common_name" root_path_ca: "root ca path" cert_path: "path for generate certificate" diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 95b21d7..3c56bee 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -3,8 +3,6 @@ package controller import ( "sync" "time" - - "go.uber.org/zap" ) var intermediateCommonNameLayout = "%s Intermediate Authority" @@ -45,22 +43,27 @@ func (s *controller) Start() error { func (s *controller) workflow() { wg := &sync.WaitGroup{} - for _, c := range s.certs.CA { + for _, c := range s.certs.RootCA { + wg.Add(1) + go func(c RootCA) { + defer wg.Done() + s.rootCA(c) + }(c) + } + wg.Wait() + + for _, c := range s.certs.IntermediateCA { wg.Add(1) - go func(c CA) { + go func(c IntermediateCA) { defer wg.Done() - if err := s.ca(c); err != nil { - zap.L().Error("ca", zap.String("common_name", c.CommonName), zap.Error(err)) - } + s.intermediateCA(c) }(c) } wg.Wait() for _, c := range s.certs.CSR { go func(c CSR) { - if err := s.csr(c); err != nil { - zap.L().Error("ca", zap.String("common_name", c.CommonName), zap.Error(err)) - } + s.csr(c) }(c) } } diff --git a/internal/controller/csr.go b/internal/controller/csr.go index a2e8b67..98efa86 100644 --- a/internal/controller/csr.go +++ b/internal/controller/csr.go @@ -9,29 +9,23 @@ import ( "go.uber.org/zap" ) -func (s *controller) csr(i CSR) error { +func (s *controller) csr(i CSR) { csr, err := s.readCertificate(i.HostPath) if csr != nil && time.Until(csr.Leaf.NotAfter) > s.certs.ReissueInterval { - return nil + return } if err != nil && !os.IsNotExist(err) { zap.L().Error("read csr", zap.String("path", i.HostPath), zap.Error(err)) - return err } cert, key, err := s.generateCSR(i) if err != nil { zap.L().Error("generate csr", zap.Error(err)) - return err } - err = s.storeCSR(i, cert, key) - if err != nil { + if err = s.storeCSR(i, cert, key); err != nil { zap.L().Error("store csr", zap.Error(err)) - return err } - - return err } func (s *controller) generateCSR(i CSR) ([]byte, []byte, error) { diff --git a/internal/controller/ca.go b/internal/controller/intermediate-ca.go similarity index 90% rename from internal/controller/ca.go rename to internal/controller/intermediate-ca.go index 349b8ac..a2b3a31 100644 --- a/internal/controller/ca.go +++ b/internal/controller/intermediate-ca.go @@ -8,7 +8,7 @@ import ( "go.uber.org/zap" ) -func (s *controller) ca(i CA) error { +func (s *controller) intermediateCA(i IntermediateCA) { storedICA, err := s.vault.Get(s.certs.VaultKV, i.CommonName+"-ca") if err != err { zap.L().Warn( @@ -37,7 +37,7 @@ func (s *controller) ca(i CA) error { ) } if err == nil { - return nil + return } } @@ -47,21 +47,17 @@ func (s *controller) ca(i CA) error { "generate intermediate-ca", zap.Error(err), ) - return err } - if err = s.storeCA(i, cert, key); err != nil { + if err = s.storeIntermediateCA(i, cert, key); err != nil { zap.L().Error( "stored intermediate-ca", zap.Error(err), ) - return err } - - return nil } -func (s *controller) generateIntermediateCA(i CA) (crt, key []byte, err error) { +func (s *controller) generateIntermediateCA(i IntermediateCA) (crt, key []byte, err error) { // create intermediate CA csrData := map[string]interface{}{ "common_name": fmt.Sprintf(intermediateCommonNameLayout, i.CommonName), @@ -104,7 +100,7 @@ func (s *controller) generateIntermediateCA(i CA) (crt, key []byte, err error) { return []byte(ica["certificate"].(string)), []byte(csr["private_key"].(string)), nil } -func (s *controller) storeCA(i CA, crt, key []byte) error { +func (s *controller) storeIntermediateCA(i IntermediateCA, crt, key []byte) error { // saving the created Intermediate CA storedICA := map[string]interface{}{ "certificate": string(crt), diff --git a/internal/controller/root-ca.go b/internal/controller/root-ca.go new file mode 100644 index 0000000..46263e9 --- /dev/null +++ b/internal/controller/root-ca.go @@ -0,0 +1,31 @@ +package controller + +import ( + "fmt" + + "go.uber.org/zap" +) + +func (s *controller) rootCA(i RootCA) { + if err := s.generateRootCA(i); err != nil { + zap.L().Error( + "generate root-ca", + zap.Error(err), + ) + } +} + +func (s *controller) generateRootCA(i RootCA) (err error) { + // create intermediate CA + csrData := map[string]interface{}{ + "common_name": i.CommonName, + "ttl": "8760h", + } + + path := i.RootPathCA + "/root/generate/internal" + _, err = s.vault.Write(path, csrData) + if err != nil { + err = fmt.Errorf("create root CA: %w", err) + } + return +} diff --git a/internal/controller/types.go b/internal/controller/types.go index b2ccbad..e5f79cd 100644 --- a/internal/controller/types.go +++ b/internal/controller/types.go @@ -5,13 +5,19 @@ import ( ) type Config struct { - VaultKV string `yaml:"vault_kv"` - ReissueInterval time.Duration `yaml:"reissue_interval"` - CA []CA `yaml:"ca,omitempty"` - CSR []CSR `yaml:"csr,omitempty"` + VaultKV string `yaml:"vault_kv"` + ReissueInterval time.Duration `yaml:"reissue_interval"` + RootCA []RootCA `yaml:"root_ca,omitempty"` + IntermediateCA []IntermediateCA `yaml:"intermediate_ca,omitempty"` + CSR []CSR `yaml:"csr,omitempty"` } -type CA struct { +type RootCA struct { + CommonName string `yaml:"common_name"` + RootPathCA string `yaml:"root_path_ca"` +} + +type IntermediateCA struct { CommonName string `yaml:"common_name"` RootPathCA string `yaml:"root_path_ca"` CertPath string `yaml:"cert_path"` From 82c42054092f6b13db92923a3f96faa711470fd3 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Sat, 18 Jun 2022 21:53:29 +0300 Subject: [PATCH 044/220] add logs --- internal/controller/controller.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 3c56bee..0eaeb90 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -3,6 +3,8 @@ package controller import ( "sync" "time" + + "go.uber.org/zap" ) var intermediateCommonNameLayout = "%s Intermediate Authority" @@ -43,6 +45,8 @@ func (s *controller) Start() error { func (s *controller) workflow() { wg := &sync.WaitGroup{} + + zap.L().Debug("root-ca") for _, c := range s.certs.RootCA { wg.Add(1) go func(c RootCA) { @@ -52,6 +56,7 @@ func (s *controller) workflow() { } wg.Wait() + zap.L().Debug("intermediate-ca") for _, c := range s.certs.IntermediateCA { wg.Add(1) go func(c IntermediateCA) { @@ -61,6 +66,7 @@ func (s *controller) workflow() { } wg.Wait() + zap.L().Debug("csr") for _, c := range s.certs.CSR { go func(c CSR) { s.csr(c) From b26c8a6a2b29907e18e7a39ffa7155c2441a7067 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Sat, 18 Jun 2022 22:06:38 +0300 Subject: [PATCH 045/220] update --- .gitignore | 3 ++- internal/controller/intermediate-ca.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 4f50485..e5080ad 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ test/ -key-keeper \ No newline at end of file +key-keeper +config.yaml diff --git a/internal/controller/intermediate-ca.go b/internal/controller/intermediate-ca.go index a2b3a31..12df5c9 100644 --- a/internal/controller/intermediate-ca.go +++ b/internal/controller/intermediate-ca.go @@ -96,7 +96,7 @@ func (s *controller) generateIntermediateCA(i IntermediateCA) (crt, key []byte, return } - zap.L().Info("ca generated", zap.String("common_name", i.CommonName)) + zap.L().Info("intermediate-ca generated", zap.String("common_name", i.CommonName)) return []byte(ica["certificate"].(string)), []byte(csr["private_key"].(string)), nil } From 35f4f1fdbc37db0da8d677dc94db3a583247994f Mon Sep 17 00:00:00 2001 From: irbgeo Date: Sat, 18 Jun 2022 22:10:56 +0300 Subject: [PATCH 046/220] update --- internal/controller/root-ca.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/controller/root-ca.go b/internal/controller/root-ca.go index 46263e9..2fcc23b 100644 --- a/internal/controller/root-ca.go +++ b/internal/controller/root-ca.go @@ -22,10 +22,12 @@ func (s *controller) generateRootCA(i RootCA) (err error) { "ttl": "8760h", } - path := i.RootPathCA + "/root/generate/internal" + path := i.RootPathCA + "/generate/internal" _, err = s.vault.Write(path, csrData) if err != nil { err = fmt.Errorf("create root CA: %w", err) + } else { + zap.L().Info("root-ca generated", zap.String("common_name", i.CommonName)) } return } From bb1cd5493cdce4908f89f7ef4314eea6c1bda4ab Mon Sep 17 00:00:00 2001 From: irbgeo Date: Sat, 18 Jun 2022 22:19:13 +0300 Subject: [PATCH 047/220] update --- internal/controller/intermediate-ca.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/controller/intermediate-ca.go b/internal/controller/intermediate-ca.go index 12df5c9..62cfcb8 100644 --- a/internal/controller/intermediate-ca.go +++ b/internal/controller/intermediate-ca.go @@ -78,7 +78,7 @@ func (s *controller) generateIntermediateCA(i IntermediateCA) (crt, key []byte, "ttl": "8760h", } - path = i.RootPathCA + "/root/sign-intermediate" + path = i.RootPathCA + "/sign-intermediate" ica, err := s.vault.Write(path, icaData) if err != nil { err = fmt.Errorf("send the intermediate CA's CSR to the root CA for signing CA: %w", err) From 9771a61191912f6e1279bcce48c0fc14a65b89ca Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Sat, 18 Jun 2022 23:11:45 +0300 Subject: [PATCH 048/220] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D0=B5=D1=82=20/root/=20=D0=B2=20=D0=BF=D1=83=D1=82=D0=B8?= =?UTF-8?q?=20=D0=B8=D0=BD=D1=82=D0=B5=D1=80=D0=BC=D0=B5=D0=B4=D0=B8=D0=B0?= =?UTF-8?q?=D1=82=20=D0=B8=20=D1=80=D1=83=D1=82=20=D1=81=D0=B5=D1=80=D1=82?= =?UTF-8?q?=D0=B8=D1=84=D0=B8=D0=BA=D0=B0=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 ++ internal/controller/intermediate-ca.go | 2 +- internal/controller/root-ca.go | 3 +-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index e5080ad..8dd5c0a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ test/ key-keeper config.yaml +role_id +secret_id diff --git a/internal/controller/intermediate-ca.go b/internal/controller/intermediate-ca.go index 62cfcb8..12df5c9 100644 --- a/internal/controller/intermediate-ca.go +++ b/internal/controller/intermediate-ca.go @@ -78,7 +78,7 @@ func (s *controller) generateIntermediateCA(i IntermediateCA) (crt, key []byte, "ttl": "8760h", } - path = i.RootPathCA + "/sign-intermediate" + path = i.RootPathCA + "/root/sign-intermediate" ica, err := s.vault.Write(path, icaData) if err != nil { err = fmt.Errorf("send the intermediate CA's CSR to the root CA for signing CA: %w", err) diff --git a/internal/controller/root-ca.go b/internal/controller/root-ca.go index 2fcc23b..bef62aa 100644 --- a/internal/controller/root-ca.go +++ b/internal/controller/root-ca.go @@ -21,8 +21,7 @@ func (s *controller) generateRootCA(i RootCA) (err error) { "common_name": i.CommonName, "ttl": "8760h", } - - path := i.RootPathCA + "/generate/internal" + path := i.RootPathCA + "/root/generate/internal" _, err = s.vault.Write(path, csrData) if err != nil { err = fmt.Errorf("create root CA: %w", err) From 86ca4a42619f190cf7d7747860f536e308497e3a Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 20 Jun 2022 15:54:53 +0300 Subject: [PATCH 049/220] refactoring --- internal/controller/{types.go => config.go} | 1 + internal/controller/intermediate-ca.go | 68 +++++++++++---------- internal/vault/{type.go => config.go} | 0 3 files changed, 38 insertions(+), 31 deletions(-) rename internal/controller/{types.go => config.go} (96%) rename internal/vault/{type.go => config.go} (100%) diff --git a/internal/controller/types.go b/internal/controller/config.go similarity index 96% rename from internal/controller/types.go rename to internal/controller/config.go index e5f79cd..8a43391 100644 --- a/internal/controller/types.go +++ b/internal/controller/config.go @@ -21,6 +21,7 @@ type IntermediateCA struct { CommonName string `yaml:"common_name"` RootPathCA string `yaml:"root_path_ca"` CertPath string `yaml:"cert_path"` + Create bool `yaml:"create"` HostPath string `yaml:"host_path"` } diff --git a/internal/controller/intermediate-ca.go b/internal/controller/intermediate-ca.go index 62cfcb8..919f287 100644 --- a/internal/controller/intermediate-ca.go +++ b/internal/controller/intermediate-ca.go @@ -9,54 +9,60 @@ import ( ) func (s *controller) intermediateCA(i IntermediateCA) { - storedICA, err := s.vault.Get(s.certs.VaultKV, i.CommonName+"-ca") - if err != err { - zap.L().Warn( - "get intermediate ca", - zap.String("name", i.CommonName+"-ca"), - zap.String("vault_kv", s.certs.VaultKV), - zap.Error(err), - ) - } - if storedICA != nil { - cert, key := []byte(storedICA["certificate"].(string)), []byte(storedICA["private_key"].(string)) - var ca *tls.Certificate - ca, err = parseToCert(cert, key) - if ca != nil && time.Until(ca.Leaf.NotAfter) < s.certs.ReissueInterval { - zap.L().Warn( - "expired intermediate-ca", - zap.Float64("until_h", time.Until(ca.Leaf.NotAfter).Hours()), - zap.Error(err), - ) - } - if err != nil { + var ( + crt, key []byte + err error + ) + + defer func() { + if err := s.storeIntermediateCA(i, crt, key); err != nil { zap.L().Error( - "analize", - zap.Any("certificate", "intermediate-ca"), + "stored intermediate-ca", zap.Error(err), ) } - if err == nil { - return - } - } + }() - cert, key, err := s.generateIntermediateCA(i) + crt, key, err = s.readIntermediateCA(i) if err != nil { zap.L().Error( - "generate intermediate-ca", + "read intermediate ca", + zap.String("common_name", i.CommonName+"-ca"), zap.Error(err), ) + } else { + return } - if err = s.storeIntermediateCA(i, cert, key); err != nil { + crt, key, err = s.generateIntermediateCA(i) + if err != nil { zap.L().Error( - "stored intermediate-ca", + "generate intermediate-ca", zap.Error(err), ) } } +func (s *controller) readIntermediateCA(i IntermediateCA) (crt, key []byte, err error) { + storedICA, err := s.vault.Get(s.certs.VaultKV, i.CommonName+"-ca") + if err != err { + err = fmt.Errorf("get from vault_kv %s : %w", s.certs.VaultKV, err) + return + } + + crt, key = []byte(storedICA["certificate"].(string)), []byte(storedICA["private_key"].(string)) + + var ca *tls.Certificate + ca, err = parseToCert(crt, key) + if err != nil { + err = fmt.Errorf("parse : %w", err) + } + if ca != nil && time.Until(ca.Leaf.NotAfter) < s.certs.ReissueInterval { + err = fmt.Errorf("expired until(h) %f", time.Until(ca.Leaf.NotAfter).Hours()) + } + return +} + func (s *controller) generateIntermediateCA(i IntermediateCA) (crt, key []byte, err error) { // create intermediate CA csrData := map[string]interface{}{ diff --git a/internal/vault/type.go b/internal/vault/config.go similarity index 100% rename from internal/vault/type.go rename to internal/vault/config.go From ce7a401499321da16e8444eb7584f1ef512a4ad3 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 20 Jun 2022 16:38:16 +0300 Subject: [PATCH 050/220] fix: --- internal/controller/intermediate-ca.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/controller/intermediate-ca.go b/internal/controller/intermediate-ca.go index 919f287..63f36ae 100644 --- a/internal/controller/intermediate-ca.go +++ b/internal/controller/intermediate-ca.go @@ -45,13 +45,12 @@ func (s *controller) intermediateCA(i IntermediateCA) { func (s *controller) readIntermediateCA(i IntermediateCA) (crt, key []byte, err error) { storedICA, err := s.vault.Get(s.certs.VaultKV, i.CommonName+"-ca") - if err != err { + if err != nil { err = fmt.Errorf("get from vault_kv %s : %w", s.certs.VaultKV, err) return } crt, key = []byte(storedICA["certificate"].(string)), []byte(storedICA["private_key"].(string)) - var ca *tls.Certificate ca, err = parseToCert(crt, key) if err != nil { From aa7f245b4b2a9f20ca78139b9c0833efead1b98c Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 20 Jun 2022 16:48:20 +0300 Subject: [PATCH 051/220] update --- internal/controller/intermediate-ca.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/controller/intermediate-ca.go b/internal/controller/intermediate-ca.go index 63f36ae..2333580 100644 --- a/internal/controller/intermediate-ca.go +++ b/internal/controller/intermediate-ca.go @@ -102,7 +102,7 @@ func (s *controller) generateIntermediateCA(i IntermediateCA) (crt, key []byte, } zap.L().Info("intermediate-ca generated", zap.String("common_name", i.CommonName)) - return []byte(ica["certificate"].(string)), []byte(csr["private_key"].(string)), nil + return []byte(csr["certificate"].(string)), []byte(csr["private_key"].(string)), nil } func (s *controller) storeIntermediateCA(i IntermediateCA, crt, key []byte) error { From 0814efa7193bbfa0ae9bc23c39eb03e452086b94 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 20 Jun 2022 16:56:41 +0300 Subject: [PATCH 052/220] update --- internal/controller/intermediate-ca.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/controller/intermediate-ca.go b/internal/controller/intermediate-ca.go index 2333580..33c5ff9 100644 --- a/internal/controller/intermediate-ca.go +++ b/internal/controller/intermediate-ca.go @@ -49,6 +49,10 @@ func (s *controller) readIntermediateCA(i IntermediateCA) (crt, key []byte, err err = fmt.Errorf("get from vault_kv %s : %w", s.certs.VaultKV, err) return } + if storedICA == nil { + err = fmt.Errorf("not found (vault_kv %s )", s.certs.VaultKV) + return + } crt, key = []byte(storedICA["certificate"].(string)), []byte(storedICA["private_key"].(string)) var ca *tls.Certificate From cda12032e0ccf575c6c09305d51a3f963fccc1b9 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 20 Jun 2022 17:25:00 +0300 Subject: [PATCH 053/220] update --- .gitignore | 1 + cmd/key-keeper/main.go | 8 ++++---- internal/controller/intermediate-ca.go | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index e5080ad..3ea873b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ test/ key-keeper config.yaml + diff --git a/cmd/key-keeper/main.go b/cmd/key-keeper/main.go index 13a9aad..423d147 100644 --- a/cmd/key-keeper/main.go +++ b/cmd/key-keeper/main.go @@ -26,11 +26,11 @@ func main() { flag.StringVar(&configPath, "config", "", "path to config file") flag.Parse() - if configPath == "" { - zap.L().Fatal("not found config param") - } + // if configPath == "" { + // zap.L().Fatal("not found config param") + // } - cfg, err := config.Read(configPath) + cfg, err := config.Read("/home/geo/projects/irbgeo/key-keeper/config.yaml") if err != nil { zap.L().Fatal("read configuration", zap.Error(err)) } diff --git a/internal/controller/intermediate-ca.go b/internal/controller/intermediate-ca.go index 33c5ff9..35504e3 100644 --- a/internal/controller/intermediate-ca.go +++ b/internal/controller/intermediate-ca.go @@ -106,7 +106,7 @@ func (s *controller) generateIntermediateCA(i IntermediateCA) (crt, key []byte, } zap.L().Info("intermediate-ca generated", zap.String("common_name", i.CommonName)) - return []byte(csr["certificate"].(string)), []byte(csr["private_key"].(string)), nil + return []byte(csr["csr"].(string)), []byte(csr["private_key"].(string)), nil } func (s *controller) storeIntermediateCA(i IntermediateCA, crt, key []byte) error { From 44e4d2450f949d5f3c05715d91b5f569e82cbd58 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 20 Jun 2022 17:38:13 +0300 Subject: [PATCH 054/220] update --- cmd/key-keeper/main.go | 8 ++++---- internal/controller/intermediate-ca.go | 4 ---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/cmd/key-keeper/main.go b/cmd/key-keeper/main.go index 423d147..13a9aad 100644 --- a/cmd/key-keeper/main.go +++ b/cmd/key-keeper/main.go @@ -26,11 +26,11 @@ func main() { flag.StringVar(&configPath, "config", "", "path to config file") flag.Parse() - // if configPath == "" { - // zap.L().Fatal("not found config param") - // } + if configPath == "" { + zap.L().Fatal("not found config param") + } - cfg, err := config.Read("/home/geo/projects/irbgeo/key-keeper/config.yaml") + cfg, err := config.Read(configPath) if err != nil { zap.L().Fatal("read configuration", zap.Error(err)) } diff --git a/internal/controller/intermediate-ca.go b/internal/controller/intermediate-ca.go index 3347133..b474a90 100644 --- a/internal/controller/intermediate-ca.go +++ b/internal/controller/intermediate-ca.go @@ -49,10 +49,6 @@ func (s *controller) readIntermediateCA(i IntermediateCA) (crt, key []byte, err err = fmt.Errorf("get from vault_kv %s : %w", s.certs.VaultKV, err) return } - if storedICA == nil { - err = fmt.Errorf("not found (vault_kv %s )", s.certs.VaultKV) - return - } crt, key = []byte(storedICA["certificate"].(string)), []byte(storedICA["private_key"].(string)) var ca *tls.Certificate From 27f0ffcfc0b400df4cfcbedc48b753ad779a1a24 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 20 Jun 2022 19:43:51 +0300 Subject: [PATCH 055/220] update --- internal/controller/intermediate-ca.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/controller/intermediate-ca.go b/internal/controller/intermediate-ca.go index b474a90..d2ad8b9 100644 --- a/internal/controller/intermediate-ca.go +++ b/internal/controller/intermediate-ca.go @@ -102,7 +102,7 @@ func (s *controller) generateIntermediateCA(i IntermediateCA) (crt, key []byte, } zap.L().Info("intermediate-ca generated", zap.String("common_name", i.CommonName)) - return []byte(csr["csr"].(string)), []byte(csr["private_key"].(string)), nil + return []byte(ica["certificate"].(string)), []byte(csr["private_key"].(string)), nil } func (s *controller) storeIntermediateCA(i IntermediateCA, crt, key []byte) error { From c6d3d8f6c3e7ed400cbfef7bd0deca49573bbdd4 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 20 Jun 2022 20:11:36 +0300 Subject: [PATCH 056/220] local | external key --- internal/controller/config.go | 11 +- internal/controller/controller.go | 7 +- ...iate-ca.go => intermediate-ca-with-key.go} | 34 +++--- .../controller/intermediate-ca-without-key.go | 101 ++++++++++++++++++ internal/controller/store.go | 14 ++- 5 files changed, 139 insertions(+), 28 deletions(-) rename internal/controller/{intermediate-ca.go => intermediate-ca-with-key.go} (66%) create mode 100644 internal/controller/intermediate-ca-without-key.go diff --git a/internal/controller/config.go b/internal/controller/config.go index 8a43391..1aa5c3c 100644 --- a/internal/controller/config.go +++ b/internal/controller/config.go @@ -18,11 +18,12 @@ type RootCA struct { } type IntermediateCA struct { - CommonName string `yaml:"common_name"` - RootPathCA string `yaml:"root_path_ca"` - CertPath string `yaml:"cert_path"` - Create bool `yaml:"create"` - HostPath string `yaml:"host_path"` + CommonName string `yaml:"common_name"` + RootPathCA string `yaml:"root_path_ca"` + CertPath string `yaml:"cert_path"` + Create bool `yaml:"create"` + WithLocalKey bool `yaml:"with_local_key"` + HostPath string `yaml:"host_path"` } type CSR struct { diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 0eaeb90..f9ffb9f 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -61,7 +61,12 @@ func (s *controller) workflow() { wg.Add(1) go func(c IntermediateCA) { defer wg.Done() - s.intermediateCA(c) + if c.WithLocalKey { + s.intermediateCAWithKey(c) + } else { + s.intermediateCAWithoutKey(c) + } + }(c) } wg.Wait() diff --git a/internal/controller/intermediate-ca.go b/internal/controller/intermediate-ca-with-key.go similarity index 66% rename from internal/controller/intermediate-ca.go rename to internal/controller/intermediate-ca-with-key.go index d2ad8b9..ac472c7 100644 --- a/internal/controller/intermediate-ca.go +++ b/internal/controller/intermediate-ca-with-key.go @@ -8,25 +8,25 @@ import ( "go.uber.org/zap" ) -func (s *controller) intermediateCA(i IntermediateCA) { +func (s *controller) intermediateCAWithKey(i IntermediateCA) { var ( crt, key []byte err error ) defer func() { - if err := s.storeIntermediateCA(i, crt, key); err != nil { + if err := s.storeIntermediateCAWithKey(i, crt, key); err != nil { zap.L().Error( - "stored intermediate-ca", + "stored intermediate ca with key", zap.Error(err), ) } }() - crt, key, err = s.readIntermediateCA(i) + crt, key, err = s.readIntermediateCAWithKey(i) if err != nil { zap.L().Error( - "read intermediate ca", + "read intermediate ca with key", zap.String("common_name", i.CommonName+"-ca"), zap.Error(err), ) @@ -34,16 +34,16 @@ func (s *controller) intermediateCA(i IntermediateCA) { return } - crt, key, err = s.generateIntermediateCA(i) + crt, key, err = s.generateIntermediateCAWithKey(i) if err != nil { zap.L().Error( - "generate intermediate-ca", + "generate intermediate ca with key", zap.Error(err), ) } } -func (s *controller) readIntermediateCA(i IntermediateCA) (crt, key []byte, err error) { +func (s *controller) readIntermediateCAWithKey(i IntermediateCA) (crt, key []byte, err error) { storedICA, err := s.vault.Get(s.certs.VaultKV, i.CommonName+"-ca") if err != nil { err = fmt.Errorf("get from vault_kv %s : %w", s.certs.VaultKV, err) @@ -62,8 +62,8 @@ func (s *controller) readIntermediateCA(i IntermediateCA) (crt, key []byte, err return } -func (s *controller) generateIntermediateCA(i IntermediateCA) (crt, key []byte, err error) { - // create intermediate CA +func (s *controller) generateIntermediateCAWithKey(i IntermediateCA) (crt, key []byte, err error) { + // create intermediate ca with key csrData := map[string]interface{}{ "common_name": fmt.Sprintf(intermediateCommonNameLayout, i.CommonName), "ttl": "8760h", @@ -72,11 +72,11 @@ func (s *controller) generateIntermediateCA(i IntermediateCA) (crt, key []byte, path := i.CertPath + "/intermediate/generate/exported" csr, err := s.vault.Write(path, csrData) if err != nil { - err = fmt.Errorf("create intermediate CA: %w", err) + err = fmt.Errorf("create: %w", err) return } - // send the intermediate CA's CSR to the root CA for signing + // send the intermediate ca with key's CSR to the root CA for signing icaData := map[string]interface{}{ "csr": csr["csr"], "format": "pem_bundle", @@ -86,18 +86,18 @@ func (s *controller) generateIntermediateCA(i IntermediateCA) (crt, key []byte, path = i.RootPathCA + "/root/sign-intermediate" ica, err := s.vault.Write(path, icaData) if err != nil { - err = fmt.Errorf("send the intermediate CA's CSR to the root CA for signing CA: %w", err) + err = fmt.Errorf("send the intermediate ca with key's CSR to the root CA for signing CA: %w", err) return } - // publish the signed certificate back to the Intermediate CA + // publish the signed certificate back to the intermediate ca with key certData := map[string]interface{}{ "certificate": ica["certificate"], } path = i.CertPath + "/intermediate/set-signed" if _, err = s.vault.Write(path, certData); err != nil { - err = fmt.Errorf("publish the signed certificate back to the Intermediate CA: %w", err) + err = fmt.Errorf("publish the signed certificate back to the intermediate ca with key: %w", err) return } @@ -105,8 +105,8 @@ func (s *controller) generateIntermediateCA(i IntermediateCA) (crt, key []byte, return []byte(ica["certificate"].(string)), []byte(csr["private_key"].(string)), nil } -func (s *controller) storeIntermediateCA(i IntermediateCA, crt, key []byte) error { - // saving the created Intermediate CA +func (s *controller) storeIntermediateCAWithKey(i IntermediateCA, crt, key []byte) error { + // saving the created intermediate ca with key storedICA := map[string]interface{}{ "certificate": string(crt), "private_key": string(key), diff --git a/internal/controller/intermediate-ca-without-key.go b/internal/controller/intermediate-ca-without-key.go new file mode 100644 index 0000000..5435784 --- /dev/null +++ b/internal/controller/intermediate-ca-without-key.go @@ -0,0 +1,101 @@ +package controller + +import ( + "fmt" + + "go.uber.org/zap" +) + +func (s *controller) intermediateCAWithoutKey(i IntermediateCA) { + var ( + crt []byte + err error + ) + + defer func() { + if err := s.storeIntermediateCAWithoutKey(i, crt, nil); err != nil { + zap.L().Error( + "stored intermediate-ca", + zap.Error(err), + ) + } + }() + + crt, err = s.readIntermediateCAWithoutKey(i) + if err != nil { + zap.L().Error( + "read intermediate ca", + zap.String("common_name", i.CommonName+"-ca"), + zap.Error(err), + ) + } else { + return + } + + crt, err = s.generateIntermediateCAWithoutKey(i) + if err != nil { + zap.L().Error( + "generate intermediate-ca", + zap.Error(err), + ) + } +} + +func (s *controller) readIntermediateCAWithoutKey(i IntermediateCA) (crt []byte, err error) { + path := i.CertPath + "/cert/ca" + ica, err := s.vault.Read(path) + if ica != nil { + return []byte(ica["certificate"].(string)), err + } + return +} + +func (s *controller) generateIntermediateCAWithoutKey(i IntermediateCA) (crt []byte, err error) { + // create intermediate CA + csrData := map[string]interface{}{ + "common_name": fmt.Sprintf(intermediateCommonNameLayout, i.CommonName), + "ttl": "8760h", + } + + path := i.CertPath + "/intermediate/generate/internal" + csr, err := s.vault.Write(path, csrData) + if err != nil { + err = fmt.Errorf("create intermediate CA: %w", err) + return + } + + // send the intermediate CA's CSR to the root CA for signing + icaData := map[string]interface{}{ + "csr": csr["csr"], + "format": "pem_bundle", + "ttl": "8760h", + } + + path = i.RootPathCA + "/root/sign-intermediate" + ica, err := s.vault.Write(path, icaData) + if err != nil { + err = fmt.Errorf("send the intermediate CA's CSR to the root CA for signing CA: %w", err) + return + } + + // publish the signed certificate back to the Intermediate CA + certData := map[string]interface{}{ + "certificate": ica["certificate"], + } + + path = i.CertPath + "/intermediate/set-signed" + if _, err = s.vault.Write(path, certData); err != nil { + err = fmt.Errorf("publish the signed certificate back to the Intermediate CA: %w", err) + return + } + + zap.L().Info("intermediate-ca generated", zap.String("common_name", i.CommonName)) + return []byte(ica["certificate"].(string)), nil +} + +func (s *controller) storeIntermediateCAWithoutKey(i IntermediateCA, crt, key []byte) error { + if err := s.storeCertificate(i.HostPath, crt, key); err != nil { + return fmt.Errorf("host path %s : %w", i.HostPath, err) + } + return nil +} diff --git a/internal/controller/store.go b/internal/controller/store.go index 3b3a461..81a74fa 100644 --- a/internal/controller/store.go +++ b/internal/controller/store.go @@ -7,13 +7,17 @@ import ( "os" ) -func (s *controller) storeCertificate(path string, cert, key []byte) error { - if err := os.WriteFile(path+".pem", cert, 0644); err != nil { - return fmt.Errorf("failed to save certificate with path %s: %w", path, err) +func (s *controller) storeCertificate(path string, crt, key []byte) error { + if crt != nil { + if err := os.WriteFile(path+".pem", crt, 0644); err != nil { + return fmt.Errorf("failed to save certificate with path %s: %w", path, err) + } } - if err := os.WriteFile(path+"-key.pem", key, 0600); err != nil { - return fmt.Errorf("failed to save key file: %w", err) + if key != nil { + if err := os.WriteFile(path+"-key.pem", key, 0600); err != nil { + return fmt.Errorf("failed to save key file: %w", err) + } } return nil } From 4ff8ef7ff538db57d5aa1cbfad31e55b54eda1d0 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 20 Jun 2022 20:24:58 +0300 Subject: [PATCH 057/220] add without key --- internal/controller/config.go | 12 ++++++------ internal/controller/controller.go | 1 - internal/controller/intermediate-ca-with-key.go | 14 ++++++++------ internal/controller/intermediate-ca-without-key.go | 14 ++++++++------ 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/internal/controller/config.go b/internal/controller/config.go index 1aa5c3c..88221de 100644 --- a/internal/controller/config.go +++ b/internal/controller/config.go @@ -18,12 +18,12 @@ type RootCA struct { } type IntermediateCA struct { - CommonName string `yaml:"common_name"` - RootPathCA string `yaml:"root_path_ca"` - CertPath string `yaml:"cert_path"` - Create bool `yaml:"create"` - WithLocalKey bool `yaml:"with_local_key"` - HostPath string `yaml:"host_path"` + CommonName string `yaml:"common_name"` + RootPathCA string `yaml:"root_path_ca"` + CertPath string `yaml:"cert_path"` + WithoutCreating bool `yaml:"without_creating"` + WithLocalKey bool `yaml:"with_local_key"` + HostPath string `yaml:"host_path"` } type CSR struct { diff --git a/internal/controller/controller.go b/internal/controller/controller.go index f9ffb9f..9adb3dd 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -66,7 +66,6 @@ func (s *controller) workflow() { } else { s.intermediateCAWithoutKey(c) } - }(c) } wg.Wait() diff --git a/internal/controller/intermediate-ca-with-key.go b/internal/controller/intermediate-ca-with-key.go index ac472c7..e1e056b 100644 --- a/internal/controller/intermediate-ca-with-key.go +++ b/internal/controller/intermediate-ca-with-key.go @@ -34,12 +34,14 @@ func (s *controller) intermediateCAWithKey(i IntermediateCA) { return } - crt, key, err = s.generateIntermediateCAWithKey(i) - if err != nil { - zap.L().Error( - "generate intermediate ca with key", - zap.Error(err), - ) + if !i.WithoutCreating { + crt, key, err = s.generateIntermediateCAWithKey(i) + if err != nil { + zap.L().Error( + "generate intermediate ca with key", + zap.Error(err), + ) + } } } diff --git a/internal/controller/intermediate-ca-without-key.go b/internal/controller/intermediate-ca-without-key.go index 5435784..0e7d2e1 100644 --- a/internal/controller/intermediate-ca-without-key.go +++ b/internal/controller/intermediate-ca-without-key.go @@ -32,12 +32,14 @@ func (s *controller) intermediateCAWithoutKey(i IntermediateCA) { return } - crt, err = s.generateIntermediateCAWithoutKey(i) - if err != nil { - zap.L().Error( - "generate intermediate-ca", - zap.Error(err), - ) + if !i.WithoutCreating { + crt, err = s.generateIntermediateCAWithoutKey(i) + if err != nil { + zap.L().Error( + "generate intermediate-ca", + zap.Error(err), + ) + } } } From b90b90e63e22ec31dc098b4cf08ffd1fbf27df2f Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 20 Jun 2022 20:31:52 +0300 Subject: [PATCH 058/220] exported key --- README.md | 4 +++ internal/controller/config.go | 12 +++---- internal/controller/controller.go | 6 ++-- ...key.go => intermediate-ca-exported-key.go} | 34 +++++++++---------- ...e-ca-without-key.go => intermediate-ca.go} | 16 ++++----- 5 files changed, 38 insertions(+), 34 deletions(-) rename internal/controller/{intermediate-ca-with-key.go => intermediate-ca-exported-key.go} (68%) rename internal/controller/{intermediate-ca-without-key.go => intermediate-ca.go} (78%) diff --git a/README.md b/README.md index 96c9dd1..fa55fce 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,10 @@ certificates: - common_name: "common_name" root_path_ca: "root ca path" cert_path: "path for generate certificate" + # флаг указывающий на генерацию с экспортируемым ключом + exporting_key: true | false + # флаг показывающий что генерация сертификата не нужна + read_only: true | false host_path: "path for store of ca in host" csr: - common_name: "common_name" diff --git a/internal/controller/config.go b/internal/controller/config.go index 88221de..c120fbe 100644 --- a/internal/controller/config.go +++ b/internal/controller/config.go @@ -18,12 +18,12 @@ type RootCA struct { } type IntermediateCA struct { - CommonName string `yaml:"common_name"` - RootPathCA string `yaml:"root_path_ca"` - CertPath string `yaml:"cert_path"` - WithoutCreating bool `yaml:"without_creating"` - WithLocalKey bool `yaml:"with_local_key"` - HostPath string `yaml:"host_path"` + CommonName string `yaml:"common_name"` + RootPathCA string `yaml:"root_path_ca"` + CertPath string `yaml:"cert_path"` + ReadOnly bool `yaml:"read_only"` + ExportedKey bool `yaml:"exported_key"` + HostPath string `yaml:"host_path"` } type CSR struct { diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 9adb3dd..e512526 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -61,10 +61,10 @@ func (s *controller) workflow() { wg.Add(1) go func(c IntermediateCA) { defer wg.Done() - if c.WithLocalKey { - s.intermediateCAWithKey(c) + if c.ExportedKey { + s.intermediateCAWithExportedKey(c) } else { - s.intermediateCAWithoutKey(c) + s.intermediateCA(c) } }(c) } diff --git a/internal/controller/intermediate-ca-with-key.go b/internal/controller/intermediate-ca-exported-key.go similarity index 68% rename from internal/controller/intermediate-ca-with-key.go rename to internal/controller/intermediate-ca-exported-key.go index e1e056b..6210a8d 100644 --- a/internal/controller/intermediate-ca-with-key.go +++ b/internal/controller/intermediate-ca-exported-key.go @@ -8,25 +8,25 @@ import ( "go.uber.org/zap" ) -func (s *controller) intermediateCAWithKey(i IntermediateCA) { +func (s *controller) intermediateCAWithExportedKey(i IntermediateCA) { var ( crt, key []byte err error ) defer func() { - if err := s.storeIntermediateCAWithKey(i, crt, key); err != nil { + if err := s.storeIntermediateCAWithExportedKey(i, crt, key); err != nil { zap.L().Error( - "stored intermediate ca with key", + "stored intermediate ca with exported key", zap.Error(err), ) } }() - crt, key, err = s.readIntermediateCAWithKey(i) + crt, key, err = s.readIntermediateCAWithExportedKey(i) if err != nil { zap.L().Error( - "read intermediate ca with key", + "read intermediate ca with exported key", zap.String("common_name", i.CommonName+"-ca"), zap.Error(err), ) @@ -34,18 +34,18 @@ func (s *controller) intermediateCAWithKey(i IntermediateCA) { return } - if !i.WithoutCreating { - crt, key, err = s.generateIntermediateCAWithKey(i) + if !i.ReadOnly { + crt, key, err = s.generateIntermediateCAWithExportedKey(i) if err != nil { zap.L().Error( - "generate intermediate ca with key", + "generate intermediate ca with exported key", zap.Error(err), ) } } } -func (s *controller) readIntermediateCAWithKey(i IntermediateCA) (crt, key []byte, err error) { +func (s *controller) readIntermediateCAWithExportedKey(i IntermediateCA) (crt, key []byte, err error) { storedICA, err := s.vault.Get(s.certs.VaultKV, i.CommonName+"-ca") if err != nil { err = fmt.Errorf("get from vault_kv %s : %w", s.certs.VaultKV, err) @@ -64,8 +64,8 @@ func (s *controller) readIntermediateCAWithKey(i IntermediateCA) (crt, key []byt return } -func (s *controller) generateIntermediateCAWithKey(i IntermediateCA) (crt, key []byte, err error) { - // create intermediate ca with key +func (s *controller) generateIntermediateCAWithExportedKey(i IntermediateCA) (crt, key []byte, err error) { + // create intermediate ca with exported key csrData := map[string]interface{}{ "common_name": fmt.Sprintf(intermediateCommonNameLayout, i.CommonName), "ttl": "8760h", @@ -78,7 +78,7 @@ func (s *controller) generateIntermediateCAWithKey(i IntermediateCA) (crt, key [ return } - // send the intermediate ca with key's CSR to the root CA for signing + // send the intermediate ca with exported key's CSR to the root CA for signing icaData := map[string]interface{}{ "csr": csr["csr"], "format": "pem_bundle", @@ -88,18 +88,18 @@ func (s *controller) generateIntermediateCAWithKey(i IntermediateCA) (crt, key [ path = i.RootPathCA + "/root/sign-intermediate" ica, err := s.vault.Write(path, icaData) if err != nil { - err = fmt.Errorf("send the intermediate ca with key's CSR to the root CA for signing CA: %w", err) + err = fmt.Errorf("send the intermediate ca with exported key's CSR to the root CA for signing CA: %w", err) return } - // publish the signed certificate back to the intermediate ca with key + // publish the signed certificate back to the intermediate ca with exported key certData := map[string]interface{}{ "certificate": ica["certificate"], } path = i.CertPath + "/intermediate/set-signed" if _, err = s.vault.Write(path, certData); err != nil { - err = fmt.Errorf("publish the signed certificate back to the intermediate ca with key: %w", err) + err = fmt.Errorf("publish the signed certificate back to the intermediate ca with exported key: %w", err) return } @@ -107,8 +107,8 @@ func (s *controller) generateIntermediateCAWithKey(i IntermediateCA) (crt, key [ return []byte(ica["certificate"].(string)), []byte(csr["private_key"].(string)), nil } -func (s *controller) storeIntermediateCAWithKey(i IntermediateCA, crt, key []byte) error { - // saving the created intermediate ca with key +func (s *controller) storeIntermediateCAWithExportedKey(i IntermediateCA, crt, key []byte) error { + // saving the created intermediate ca with exported key storedICA := map[string]interface{}{ "certificate": string(crt), "private_key": string(key), diff --git a/internal/controller/intermediate-ca-without-key.go b/internal/controller/intermediate-ca.go similarity index 78% rename from internal/controller/intermediate-ca-without-key.go rename to internal/controller/intermediate-ca.go index 0e7d2e1..b6e8c55 100644 --- a/internal/controller/intermediate-ca-without-key.go +++ b/internal/controller/intermediate-ca.go @@ -6,14 +6,14 @@ import ( "go.uber.org/zap" ) -func (s *controller) intermediateCAWithoutKey(i IntermediateCA) { +func (s *controller) intermediateCA(i IntermediateCA) { var ( crt []byte err error ) defer func() { - if err := s.storeIntermediateCAWithoutKey(i, crt, nil); err != nil { + if err := s.storeIntermediateCA(i, crt, nil); err != nil { zap.L().Error( "stored intermediate-ca", zap.Error(err), @@ -21,7 +21,7 @@ func (s *controller) intermediateCAWithoutKey(i IntermediateCA) { } }() - crt, err = s.readIntermediateCAWithoutKey(i) + crt, err = s.readIntermediateCA(i) if err != nil { zap.L().Error( "read intermediate ca", @@ -32,8 +32,8 @@ func (s *controller) intermediateCAWithoutKey(i IntermediateCA) { return } - if !i.WithoutCreating { - crt, err = s.generateIntermediateCAWithoutKey(i) + if !i.ReadOnly { + crt, err = s.generateIntermediateCA(i) if err != nil { zap.L().Error( "generate intermediate-ca", @@ -43,7 +43,7 @@ func (s *controller) intermediateCAWithoutKey(i IntermediateCA) { } } -func (s *controller) readIntermediateCAWithoutKey(i IntermediateCA) (crt []byte, err error) { +func (s *controller) readIntermediateCA(i IntermediateCA) (crt []byte, err error) { path := i.CertPath + "/cert/ca" ica, err := s.vault.Read(path) if ica != nil { @@ -52,7 +52,7 @@ func (s *controller) readIntermediateCAWithoutKey(i IntermediateCA) (crt []byte, return } -func (s *controller) generateIntermediateCAWithoutKey(i IntermediateCA) (crt []byte, err error) { +func (s *controller) generateIntermediateCA(i IntermediateCA) (crt []byte, err error) { // create intermediate CA csrData := map[string]interface{}{ "common_name": fmt.Sprintf(intermediateCommonNameLayout, i.CommonName), @@ -95,7 +95,7 @@ func (s *controller) generateIntermediateCAWithoutKey(i IntermediateCA) (crt []b return []byte(ica["certificate"].(string)), nil } -func (s *controller) storeIntermediateCAWithoutKey(i IntermediateCA, crt, key []byte) error { +func (s *controller) storeIntermediateCA(i IntermediateCA, crt, key []byte) error { if err := s.storeCertificate(i.HostPath, crt, key); err != nil { return fmt.Errorf("host path %s : %w", i.HostPath, err) } From 56c4c85e53b5014446991e05d87da114d0f7eef7 Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Mon, 20 Jun 2022 23:07:56 +0300 Subject: [PATCH 059/220] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D0=B5=D1=82=20=D0=BF=D1=80=D0=B8=D0=BC=D0=B5=D1=80=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=BD=D1=84=D0=B8=D0=B3=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config.example.yaml | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 config.example.yaml diff --git a/config.example.yaml b/config.example.yaml new file mode 100644 index 0000000..f5aff77 --- /dev/null +++ b/config.example.yaml @@ -0,0 +1,38 @@ +--- +vault: + address: "http://${VAULT_IP}" # Адрес волта + bootstrap_token: ${VAULT_TOKEN} # Токен для получения secret_id и role_id + # С secret_id и role_id происходит базовая авторизация и получения временного токена. + local_path_to_role_id: "role_id" # Путь где будет сохранен файл с role_id + local_path_to_secret_id: "secret_id" # Путь где будет сохранен файл с secret_id + approle_path: clusters/cluster-1/approle # Путь до аппроли + approle_name: test-role # Название аппроли (для теста выдели аппроль и навесь рут) + request_timeout: "10m" # Таймаут ответа Vault +certificates: +# Для совместного использования приватного ключа CA,Intermidiat +# - public and private помещается в KV с наименованием ${COMMON_NAME} + vault_kv: "clusters/cluster-1/kv" + reissue_interval: "1d" # интервал перевыпуск - за сутки до истечения перевыпустить. (Хардкод - проверяет раз в час) + +# Блок Root_CA отвечает за выпуск корневых сертификатов - на выход не получаем ни сертификат ни ключ от него +# что бы все сертификаты выпускались только с Intermediate. + root_ca: + - common_name: "test" # CN + root_path_ca: "clusters/cluster-1/pki/root" # Путь к сейфу + +# Блок Intermediate_ca отвечает за выпуск промежуточных сертификатов +# Все сертификаты выпускаются в этих сейфах + intermediate_ca: + - common_name: "kubernetes" # CN + root_path_ca: "clusters/cluster-1/pki/root" # Путь к сейфу корневого CA + cert_path: "clusters/cluster-1/pki/kubernetes" # Путь к сейфу Inermediate CA + host_path: "/etc/kubernetes/pki/ca/root-ca" # Локальный путь, где будет размещен public / private keys + exported_key: false # Этот флаг заказывает Inermediate типа internal/external (в отпут придет private-key или нет) + read_only: false # Этот флаг отвечает за сценарий создания нового CA или чтение существующего. + + csr: + + - common_name: "system:kube-apiserver-front-proxy-client" # CN + role: "base-role" # system_masters_client # Роль в которой прописаны критерии сертификата (usages,access_ip,access_san,etc) + host_path: "/etc/kubernetes/pki/certs/kube-apiserver/cert" # Локальный путь, где будет размещен public / private keys + cert_path: "clusters/cluster-1/pki/kube-apiserver" # Путь к сейфу Inermediate CA где будет заказан сертификат From ffd4601603dbc48b93667a4f36d5ce8bcbb26045 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 21 Jun 2022 11:55:59 +0300 Subject: [PATCH 060/220] update --- README.md | 4 ++-- internal/controller/config.go | 2 +- internal/controller/intermediate-ca-exported-key.go | 3 +-- internal/controller/intermediate-ca.go | 4 ++-- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index fa55fce..7944913 100644 --- a/README.md +++ b/README.md @@ -22,9 +22,9 @@ certificates: root_path_ca: "root ca path" cert_path: "path for generate certificate" # флаг указывающий на генерацию с экспортируемым ключом - exporting_key: true | false + exported_key: true | false # флаг показывающий что генерация сертификата не нужна - read_only: true | false + generate: true | false host_path: "path for store of ca in host" csr: - common_name: "common_name" diff --git a/internal/controller/config.go b/internal/controller/config.go index c120fbe..b79e7eb 100644 --- a/internal/controller/config.go +++ b/internal/controller/config.go @@ -21,7 +21,7 @@ type IntermediateCA struct { CommonName string `yaml:"common_name"` RootPathCA string `yaml:"root_path_ca"` CertPath string `yaml:"cert_path"` - ReadOnly bool `yaml:"read_only"` + Generate bool `yaml:"generate"` ExportedKey bool `yaml:"exported_key"` HostPath string `yaml:"host_path"` } diff --git a/internal/controller/intermediate-ca-exported-key.go b/internal/controller/intermediate-ca-exported-key.go index 6210a8d..8cca6f5 100644 --- a/internal/controller/intermediate-ca-exported-key.go +++ b/internal/controller/intermediate-ca-exported-key.go @@ -33,8 +33,7 @@ func (s *controller) intermediateCAWithExportedKey(i IntermediateCA) { } else { return } - - if !i.ReadOnly { + if i.Generate { crt, key, err = s.generateIntermediateCAWithExportedKey(i) if err != nil { zap.L().Error( diff --git a/internal/controller/intermediate-ca.go b/internal/controller/intermediate-ca.go index b6e8c55..97e4185 100644 --- a/internal/controller/intermediate-ca.go +++ b/internal/controller/intermediate-ca.go @@ -32,7 +32,7 @@ func (s *controller) intermediateCA(i IntermediateCA) { return } - if !i.ReadOnly { + if i.Generate { crt, err = s.generateIntermediateCA(i) if err != nil { zap.L().Error( @@ -44,7 +44,7 @@ func (s *controller) intermediateCA(i IntermediateCA) { } func (s *controller) readIntermediateCA(i IntermediateCA) (crt []byte, err error) { - path := i.CertPath + "/cert/ca" + path := i.CertPath + "/cert/ca_chain" ica, err := s.vault.Read(path) if ica != nil { return []byte(ica["certificate"].(string)), err From 04045ee8e63a50f76c8b29dcebe2af6fcee47be7 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 21 Jun 2022 11:57:31 +0300 Subject: [PATCH 061/220] update --- config.example.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/config.example.yaml b/config.example.yaml index f5aff77..9582d9b 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -28,10 +28,9 @@ certificates: cert_path: "clusters/cluster-1/pki/kubernetes" # Путь к сейфу Inermediate CA host_path: "/etc/kubernetes/pki/ca/root-ca" # Локальный путь, где будет размещен public / private keys exported_key: false # Этот флаг заказывает Inermediate типа internal/external (в отпут придет private-key или нет) - read_only: false # Этот флаг отвечает за сценарий создания нового CA или чтение существующего. + generate: false # Этот флаг отвечает за сценарий создания нового CA или чтение существующего. csr: - - common_name: "system:kube-apiserver-front-proxy-client" # CN role: "base-role" # system_masters_client # Роль в которой прописаны критерии сертификата (usages,access_ip,access_san,etc) host_path: "/etc/kubernetes/pki/certs/kube-apiserver/cert" # Локальный путь, где будет размещен public / private keys From a088816389ae7a47602a84067c56a3a238b7e05b Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 21 Jun 2022 12:00:01 +0300 Subject: [PATCH 062/220] up --- README.md | 64 +++++++++++++++++++++++---------------------- config.example.yaml | 37 -------------------------- 2 files changed, 33 insertions(+), 68 deletions(-) diff --git a/README.md b/README.md index 7944913..848d0fb 100644 --- a/README.md +++ b/README.md @@ -3,41 +3,43 @@ Example config.yml ```yaml +--- vault: - address: "address vault" - bootstrap_token: "unexpired token" - approle_path: "role-path" - approle_name: "role-name" - local_path_to_role_id: "path to local role id" - local_path_to_secret_id: "path to local secret id" - request_timeout: "timeout request: 1s, 3m, 5h" + address: "http://${VAULT_IP}" # Адрес волта + bootstrap_token: ${VAULT_TOKEN} # Токен для получения secret_id и role_id + # С secret_id и role_id происходит базовая авторизация и получения временного токена. + local_path_to_role_id: "role_id" # Путь где будет сохранен файл с role_id + local_path_to_secret_id: "secret_id" # Путь где будет сохранен файл с secret_id + approle_path: clusters/cluster-1/approle # Путь до аппроли + approle_name: test-role # Название аппроли (для теста выдели аппроль и навесь рут) + request_timeout: "10m" # Таймаут ответа Vault certificates: - vault_kv: "path for kv" - reissue_interval: "interval for initialization reissue certificate: 1s, 3m, 5h" - ca: - - common_name: "common_name" - root_path_ca: "root ca path" + # Для совместного использования приватного ключа CA,Intermidiat + # - public and private помещается в KV с наименованием ${COMMON_NAME} + vault_kv: "clusters/cluster-1/kv" + reissue_interval: "1d" # интервал перевыпуск - за сутки до истечения перевыпустить. (Хардкод - проверяет раз в час) + + # Блок Root_CA отвечает за выпуск корневых сертификатов - на выход не получаем ни сертификат ни ключ от него + # что бы все сертификаты выпускались только с Intermediate. + root_ca: + - common_name: "test" # CN + root_path_ca: "clusters/cluster-1/pki/root" # Путь к сейфу + + # Блок Intermediate_ca отвечает за выпуск промежуточных сертификатов + # Все сертификаты выпускаются в этих сейфах intermediate_ca: - - common_name: "common_name" - root_path_ca: "root ca path" - cert_path: "path for generate certificate" - # флаг указывающий на генерацию с экспортируемым ключом - exported_key: true | false - # флаг показывающий что генерация сертификата не нужна - generate: true | false - host_path: "path for store of ca in host" + - common_name: "kubernetes" # CN + root_path_ca: "clusters/cluster-1/pki/root" # Путь к сейфу корневого CA + cert_path: "clusters/cluster-1/pki/kubernetes" # Путь к сейфу Inermediate CA + host_path: "/etc/kubernetes/pki/ca/root-ca" # Локальный путь, где будет размещен public / private keys + exported_key: false # Этот флаг заказывает Inermediate типа internal/external (в отпут придет private-key или нет) + generate: false # Этот флаг отвечает за сценарий создания нового CA или чтение существующего. + csr: - - common_name: "common_name" - hosts: - - "host1" - - "host2" - ips: - - "127.127.0.7" - - "127.127.0.9" - root_path_ca: "root ca path" - cert_path: "path for generate certificate" - role: "role for generate cert" - host_path: "path for store of ca in host" + - common_name: "system:kube-apiserver-front-proxy-client" # CN + role: "base-role" # system_masters_client # Роль в которой прописаны критерии сертификата (usages,access_ip,access_san,etc) + host_path: "/etc/kubernetes/pki/certs/kube-apiserver/cert" # Локальный путь, где будет размещен public / private keys + cert_path: "clusters/cluster-1/pki/kube-apiserver" # Путь к сейфу Inermediate CA где будет заказан сертификат ``` Build: diff --git a/config.example.yaml b/config.example.yaml index 9582d9b..e69de29 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -1,37 +0,0 @@ ---- -vault: - address: "http://${VAULT_IP}" # Адрес волта - bootstrap_token: ${VAULT_TOKEN} # Токен для получения secret_id и role_id - # С secret_id и role_id происходит базовая авторизация и получения временного токена. - local_path_to_role_id: "role_id" # Путь где будет сохранен файл с role_id - local_path_to_secret_id: "secret_id" # Путь где будет сохранен файл с secret_id - approle_path: clusters/cluster-1/approle # Путь до аппроли - approle_name: test-role # Название аппроли (для теста выдели аппроль и навесь рут) - request_timeout: "10m" # Таймаут ответа Vault -certificates: -# Для совместного использования приватного ключа CA,Intermidiat -# - public and private помещается в KV с наименованием ${COMMON_NAME} - vault_kv: "clusters/cluster-1/kv" - reissue_interval: "1d" # интервал перевыпуск - за сутки до истечения перевыпустить. (Хардкод - проверяет раз в час) - -# Блок Root_CA отвечает за выпуск корневых сертификатов - на выход не получаем ни сертификат ни ключ от него -# что бы все сертификаты выпускались только с Intermediate. - root_ca: - - common_name: "test" # CN - root_path_ca: "clusters/cluster-1/pki/root" # Путь к сейфу - -# Блок Intermediate_ca отвечает за выпуск промежуточных сертификатов -# Все сертификаты выпускаются в этих сейфах - intermediate_ca: - - common_name: "kubernetes" # CN - root_path_ca: "clusters/cluster-1/pki/root" # Путь к сейфу корневого CA - cert_path: "clusters/cluster-1/pki/kubernetes" # Путь к сейфу Inermediate CA - host_path: "/etc/kubernetes/pki/ca/root-ca" # Локальный путь, где будет размещен public / private keys - exported_key: false # Этот флаг заказывает Inermediate типа internal/external (в отпут придет private-key или нет) - generate: false # Этот флаг отвечает за сценарий создания нового CA или чтение существующего. - - csr: - - common_name: "system:kube-apiserver-front-proxy-client" # CN - role: "base-role" # system_masters_client # Роль в которой прописаны критерии сертификата (usages,access_ip,access_san,etc) - host_path: "/etc/kubernetes/pki/certs/kube-apiserver/cert" # Локальный путь, где будет размещен public / private keys - cert_path: "clusters/cluster-1/pki/kube-apiserver" # Путь к сейфу Inermediate CA где будет заказан сертификат From e37090d4cd45f581667a9c9fe77b6fdfb1a94868 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 21 Jun 2022 12:00:05 +0300 Subject: [PATCH 063/220] up --- config.example.yaml | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 config.example.yaml diff --git a/config.example.yaml b/config.example.yaml deleted file mode 100644 index e69de29..0000000 From 479965255e50044b9a84bfe811374372ef469abc Mon Sep 17 00:00:00 2001 From: irbgeo Date: Wed, 22 Jun 2022 17:07:31 +0300 Subject: [PATCH 064/220] update --- README.md | 5 ++ cmd/key-keeper/main.go | 2 +- internal/config/config.go | 4 +- internal/controller/config.go | 14 +++++ internal/controller/controller.go | 24 +++++--- internal/controller/csr.go | 2 +- .../intermediate-ca-exported-key.go | 8 +-- internal/controller/rsa.go | 59 +++++++++++++++++++ internal/controller/store.go | 11 ++++ 9 files changed, 113 insertions(+), 16 deletions(-) create mode 100644 internal/controller/rsa.go diff --git a/README.md b/README.md index 848d0fb..523a435 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,11 @@ certificates: role: "base-role" # system_masters_client # Роль в которой прописаны критерии сертификата (usages,access_ip,access_san,etc) host_path: "/etc/kubernetes/pki/certs/kube-apiserver/cert" # Локальный путь, где будет размещен public / private keys cert_path: "clusters/cluster-1/pki/kube-apiserver" # Путь к сейфу Inermediate CA где будет заказан сертификат +keys: + vault_kv: "" + + rsa: + - host_path: "" ``` Build: diff --git a/cmd/key-keeper/main.go b/cmd/key-keeper/main.go index 13a9aad..fca39e8 100644 --- a/cmd/key-keeper/main.go +++ b/cmd/key-keeper/main.go @@ -46,7 +46,7 @@ func main() { cntl := controller.New( v, - cfg.Certificates, + cfg.Controller, ) go func() { diff --git a/internal/config/config.go b/internal/config/config.go index ec6a5cb..bdf0860 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -11,8 +11,8 @@ import ( ) type Config struct { - Vault vault.Config `yaml:"vault"` - Certificates controller.Config `yaml:"certificates"` + Vault vault.Config `yaml:"vault"` + Controller controller.Config `yaml:",inline"` } // Read config by path. diff --git a/internal/controller/config.go b/internal/controller/config.go index b79e7eb..a9090a9 100644 --- a/internal/controller/config.go +++ b/internal/controller/config.go @@ -5,6 +5,11 @@ import ( ) type Config struct { + Certificates Certificates `json:"certificates"` + Keys Keys `json:"keys"` +} + +type Certificates struct { VaultKV string `yaml:"vault_kv"` ReissueInterval time.Duration `yaml:"reissue_interval"` RootCA []RootCA `yaml:"root_ca,omitempty"` @@ -34,3 +39,12 @@ type CSR struct { Role string `yaml:"role"` HostPath string `yaml:"host_path"` } + +type Keys struct { + VaultKV string `yaml:"vault_kv"` + RSA []RSA `yaml:"rsa"` +} + +type RSA struct { + HostPath string `yaml:"host_path"` +} diff --git a/internal/controller/controller.go b/internal/controller/controller.go index e512526..501ab89 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -19,13 +19,13 @@ type vault interface { type controller struct { vault vault - certs Config + cfg Config } func New(store vault, certs Config) *controller { c := &controller{ vault: store, - certs: certs, + cfg: certs, } return c } @@ -46,8 +46,8 @@ func (s *controller) Start() error { func (s *controller) workflow() { wg := &sync.WaitGroup{} - zap.L().Debug("root-ca") - for _, c := range s.certs.RootCA { + zap.L().Debug("certificate-root-ca") + for _, c := range s.cfg.Certificates.RootCA { wg.Add(1) go func(c RootCA) { defer wg.Done() @@ -56,8 +56,8 @@ func (s *controller) workflow() { } wg.Wait() - zap.L().Debug("intermediate-ca") - for _, c := range s.certs.IntermediateCA { + zap.L().Debug("certificate-intermediate-ca") + for _, c := range s.cfg.Certificates.IntermediateCA { wg.Add(1) go func(c IntermediateCA) { defer wg.Done() @@ -70,10 +70,18 @@ func (s *controller) workflow() { } wg.Wait() - zap.L().Debug("csr") - for _, c := range s.certs.CSR { + zap.L().Debug("certificate-csr") + for _, c := range s.cfg.Certificates.CSR { go func(c CSR) { s.csr(c) }(c) } + + zap.L().Debug("key-rsa") + for _, k := range s.cfg.Keys.RSA { + go func(k RSA) { + s.rsa(k) + }(k) + } + } diff --git a/internal/controller/csr.go b/internal/controller/csr.go index 98efa86..0a83c66 100644 --- a/internal/controller/csr.go +++ b/internal/controller/csr.go @@ -11,7 +11,7 @@ import ( func (s *controller) csr(i CSR) { csr, err := s.readCertificate(i.HostPath) - if csr != nil && time.Until(csr.Leaf.NotAfter) > s.certs.ReissueInterval { + if csr != nil && time.Until(csr.Leaf.NotAfter) > s.cfg.Certificates.ReissueInterval { return } if err != nil && !os.IsNotExist(err) { diff --git a/internal/controller/intermediate-ca-exported-key.go b/internal/controller/intermediate-ca-exported-key.go index 8cca6f5..89d7c5d 100644 --- a/internal/controller/intermediate-ca-exported-key.go +++ b/internal/controller/intermediate-ca-exported-key.go @@ -45,9 +45,9 @@ func (s *controller) intermediateCAWithExportedKey(i IntermediateCA) { } func (s *controller) readIntermediateCAWithExportedKey(i IntermediateCA) (crt, key []byte, err error) { - storedICA, err := s.vault.Get(s.certs.VaultKV, i.CommonName+"-ca") + storedICA, err := s.vault.Get(s.cfg.Certificates.VaultKV, i.CommonName+"-ca") if err != nil { - err = fmt.Errorf("get from vault_kv %s : %w", s.certs.VaultKV, err) + err = fmt.Errorf("get from vault_kv %s : %w", s.cfg.Certificates.VaultKV, err) return } @@ -57,7 +57,7 @@ func (s *controller) readIntermediateCAWithExportedKey(i IntermediateCA) (crt, k if err != nil { err = fmt.Errorf("parse : %w", err) } - if ca != nil && time.Until(ca.Leaf.NotAfter) < s.certs.ReissueInterval { + if ca != nil && time.Until(ca.Leaf.NotAfter) < s.cfg.Certificates.ReissueInterval { err = fmt.Errorf("expired until(h) %f", time.Until(ca.Leaf.NotAfter).Hours()) } return @@ -112,7 +112,7 @@ func (s *controller) storeIntermediateCAWithExportedKey(i IntermediateCA, crt, k "certificate": string(crt), "private_key": string(key), } - if err := s.vault.Put(s.certs.VaultKV, i.CommonName+"-ca", storedICA); err != nil { + if err := s.vault.Put(s.cfg.Certificates.VaultKV, i.CommonName+"-ca", storedICA); err != nil { return fmt.Errorf("saving in vault: %w", err) } diff --git a/internal/controller/rsa.go b/internal/controller/rsa.go new file mode 100644 index 0000000..8c49767 --- /dev/null +++ b/internal/controller/rsa.go @@ -0,0 +1,59 @@ +package controller + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "fmt" + + "go.uber.org/zap" +) + +func (s *controller) rsa(i RSA) { + crt, key, err := s.generateRSA() + if err != nil { + zap.L().Error("generate csr", zap.Error(err)) + } + + if err = s.storeRSA(i, crt, key); err != nil { + zap.L().Error("store csr", zap.Error(err)) + } +} + +func (s *controller) generateRSA() (private []byte, public []byte, err error) { + privateKey, err := rsa.GenerateKey(rand.Reader, 4096) + if err != nil { + return + } + + private = pem.EncodeToMemory( + &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(privateKey), + }, + ) + + public = pem.EncodeToMemory( + &pem.Block{ + Type: "RSA PUBLIC KEY", + Bytes: x509.MarshalPKCS1PublicKey(privateKey.Public().(*rsa.PublicKey)), + }, + ) + return +} + +func (s *controller) storeRSA(i RSA, private, public []byte) error { + storedRSA := map[string]interface{}{ + "private": string(private), + "public": string(public), + } + if err := s.vault.Put(s.cfg.Keys.VaultKV, "rsa", storedRSA); err != nil { + return fmt.Errorf("saving in vault: %w", err) + } + + if err := s.storeKey(i.HostPath, private, public); err != nil { + return fmt.Errorf("host path %s : %w", i.HostPath, err) + } + return nil +} diff --git a/internal/controller/store.go b/internal/controller/store.go index 81a74fa..3f85a3f 100644 --- a/internal/controller/store.go +++ b/internal/controller/store.go @@ -7,6 +7,17 @@ import ( "os" ) +func (s *controller) storeKey(path string, privare, public []byte) error { + if err := os.WriteFile(path+".pem", privare, 0600); err != nil { + return fmt.Errorf("failed to save privare key with path %s: %w", path, err) + } + + if err := os.WriteFile(path+".pub", public, 0600); err != nil { + return fmt.Errorf("failed to public key file: %w", err) + } + return nil +} + func (s *controller) storeCertificate(path string, crt, key []byte) error { if crt != nil { if err := os.WriteFile(path+".pem", crt, 0644); err != nil { From cfe2fad0072ebea47dafa49fae9d78698557505a Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 23 Jun 2022 15:21:42 +0300 Subject: [PATCH 065/220] rsa key in kv name --- internal/controller/rsa.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/controller/rsa.go b/internal/controller/rsa.go index 8c49767..cafec0f 100644 --- a/internal/controller/rsa.go +++ b/internal/controller/rsa.go @@ -6,6 +6,7 @@ import ( "crypto/x509" "encoding/pem" "fmt" + "path" "go.uber.org/zap" ) @@ -48,7 +49,8 @@ func (s *controller) storeRSA(i RSA, private, public []byte) error { "private": string(private), "public": string(public), } - if err := s.vault.Put(s.cfg.Keys.VaultKV, "rsa", storedRSA); err != nil { + _, name := path.Split(i.HostPath) + if err := s.vault.Put(s.cfg.Keys.VaultKV, name, storedRSA); err != nil { return fmt.Errorf("saving in vault: %w", err) } From d3f311ec4972c1c32ad4efc39e3123861839b2c0 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 23 Jun 2022 15:27:41 +0300 Subject: [PATCH 066/220] up --- internal/controller/root-ca.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/controller/root-ca.go b/internal/controller/root-ca.go index bef62aa..b4021ab 100644 --- a/internal/controller/root-ca.go +++ b/internal/controller/root-ca.go @@ -22,10 +22,11 @@ func (s *controller) generateRootCA(i RootCA) (err error) { "ttl": "8760h", } path := i.RootPathCA + "/root/generate/internal" - _, err = s.vault.Write(path, csrData) + r, err := s.vault.Write(path, csrData) if err != nil { err = fmt.Errorf("create root CA: %w", err) } else { + fmt.Println(r) zap.L().Info("root-ca generated", zap.String("common_name", i.CommonName)) } return From c538cd1979191ba607828d6acec11cb5f3137b4e Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 23 Jun 2022 16:03:34 +0300 Subject: [PATCH 067/220] update --- internal/controller/root-ca.go | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/internal/controller/root-ca.go b/internal/controller/root-ca.go index b4021ab..dd4f450 100644 --- a/internal/controller/root-ca.go +++ b/internal/controller/root-ca.go @@ -7,6 +7,18 @@ import ( ) func (s *controller) rootCA(i RootCA) { + isExist, err := s.isExistRootCA(i) + if err != nil { + zap.L().Error( + "generate root-ca", + zap.Error(err), + ) + } + + if isExist { + return + } + if err := s.generateRootCA(i); err != nil { zap.L().Error( "generate root-ca", @@ -15,19 +27,29 @@ func (s *controller) rootCA(i RootCA) { } } -func (s *controller) generateRootCA(i RootCA) (err error) { +func (s *controller) isExistRootCA(i RootCA) (bool, error) { + path := i.RootPathCA + "/cert/ca" + rootCA, err := s.vault.Read(path) + if err != nil { + err = fmt.Errorf("create root CA: %w", err) + } else { + zap.L().Info("root-ca generated", zap.String("common_name", i.CommonName)) + } + return rootCA == nil, err +} + +func (s *controller) generateRootCA(i RootCA) error { // create intermediate CA - csrData := map[string]interface{}{ + rootCAData := map[string]interface{}{ "common_name": i.CommonName, "ttl": "8760h", } path := i.RootPathCA + "/root/generate/internal" - r, err := s.vault.Write(path, csrData) + _, err := s.vault.Write(path, rootCAData) if err != nil { err = fmt.Errorf("create root CA: %w", err) } else { - fmt.Println(r) zap.L().Info("root-ca generated", zap.String("common_name", i.CommonName)) } - return + return err } From da8a151111e75039c5d0b60159e173045fbebe08 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 23 Jun 2022 16:04:34 +0300 Subject: [PATCH 068/220] update --- internal/controller/root-ca.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/internal/controller/root-ca.go b/internal/controller/root-ca.go index dd4f450..aeeebee 100644 --- a/internal/controller/root-ca.go +++ b/internal/controller/root-ca.go @@ -31,10 +31,9 @@ func (s *controller) isExistRootCA(i RootCA) (bool, error) { path := i.RootPathCA + "/cert/ca" rootCA, err := s.vault.Read(path) if err != nil { - err = fmt.Errorf("create root CA: %w", err) - } else { - zap.L().Info("root-ca generated", zap.String("common_name", i.CommonName)) + err = fmt.Errorf("read root CA: %w", err) } + fmt.Println(rootCA) return rootCA == nil, err } From bb752c7d67c598a072c6ea7f8a545956c99f2c77 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 23 Jun 2022 16:12:43 +0300 Subject: [PATCH 069/220] update --- internal/controller/root-ca.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/internal/controller/root-ca.go b/internal/controller/root-ca.go index aeeebee..e4a3e8f 100644 --- a/internal/controller/root-ca.go +++ b/internal/controller/root-ca.go @@ -9,12 +9,11 @@ import ( func (s *controller) rootCA(i RootCA) { isExist, err := s.isExistRootCA(i) if err != nil { - zap.L().Error( - "generate root-ca", + zap.L().Warn( + "existing root-ca", zap.Error(err), ) } - if isExist { return } @@ -24,7 +23,9 @@ func (s *controller) rootCA(i RootCA) { "generate root-ca", zap.Error(err), ) + return } + zap.L().Info("root-ca generated", zap.String("common_name", i.CommonName)) } func (s *controller) isExistRootCA(i RootCA) (bool, error) { @@ -34,7 +35,7 @@ func (s *controller) isExistRootCA(i RootCA) (bool, error) { err = fmt.Errorf("read root CA: %w", err) } fmt.Println(rootCA) - return rootCA == nil, err + return rootCA != nil, err } func (s *controller) generateRootCA(i RootCA) error { @@ -47,8 +48,6 @@ func (s *controller) generateRootCA(i RootCA) error { _, err := s.vault.Write(path, rootCAData) if err != nil { err = fmt.Errorf("create root CA: %w", err) - } else { - zap.L().Info("root-ca generated", zap.String("common_name", i.CommonName)) } return err } From 12ca89835df4591f452c022d7e20feb66c8521c6 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 23 Jun 2022 16:54:14 +0300 Subject: [PATCH 070/220] up --- internal/controller/config.go | 1 + internal/controller/root-ca.go | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/controller/config.go b/internal/controller/config.go index a9090a9..68b71f3 100644 --- a/internal/controller/config.go +++ b/internal/controller/config.go @@ -4,6 +4,7 @@ import ( "time" ) +// Config for work controller. type Config struct { Certificates Certificates `json:"certificates"` Keys Keys `json:"keys"` diff --git a/internal/controller/root-ca.go b/internal/controller/root-ca.go index e4a3e8f..9b1b025 100644 --- a/internal/controller/root-ca.go +++ b/internal/controller/root-ca.go @@ -34,12 +34,10 @@ func (s *controller) isExistRootCA(i RootCA) (bool, error) { if err != nil { err = fmt.Errorf("read root CA: %w", err) } - fmt.Println(rootCA) return rootCA != nil, err } func (s *controller) generateRootCA(i RootCA) error { - // create intermediate CA rootCAData := map[string]interface{}{ "common_name": i.CommonName, "ttl": "8760h", From a9e3a4d8c9a403c29ad7d033f22a6c0a0f128eca Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 23 Jun 2022 19:43:07 +0300 Subject: [PATCH 071/220] up --- internal/controller/config.go | 1 + internal/controller/csr.go | 15 ++++++++++--- internal/controller/root-ca.go | 2 ++ internal/controller/rsa.go | 39 ++++++++++++++++++++++++++++------ 4 files changed, 47 insertions(+), 10 deletions(-) diff --git a/internal/controller/config.go b/internal/controller/config.go index 68b71f3..1246713 100644 --- a/internal/controller/config.go +++ b/internal/controller/config.go @@ -47,5 +47,6 @@ type Keys struct { } type RSA struct { + Name string `yaml:"name"` HostPath string `yaml:"host_path"` } diff --git a/internal/controller/csr.go b/internal/controller/csr.go index 0a83c66..d057e6e 100644 --- a/internal/controller/csr.go +++ b/internal/controller/csr.go @@ -20,12 +20,22 @@ func (s *controller) csr(i CSR) { cert, key, err := s.generateCSR(i) if err != nil { - zap.L().Error("generate csr", zap.Error(err)) + zap.L().Error( + "generate csr", + zap.String("common_name", i.CommonName), + zap.Error(err), + ) } if err = s.storeCSR(i, cert, key); err != nil { - zap.L().Error("store csr", zap.Error(err)) + zap.L().Error( + "store csr", + zap.String("common_name", i.CommonName), + zap.Error(err), + ) + return } + zap.L().Info("csr generated", zap.String("common_name", i.CommonName)) } func (s *controller) generateCSR(i CSR) ([]byte, []byte, error) { @@ -40,7 +50,6 @@ func (s *controller) generateCSR(i CSR) ([]byte, []byte, error) { return nil, nil, fmt.Errorf("generate with path %s : %w", path, err) } - zap.L().Info("csr generated", zap.String("common_name", i.CommonName)) return []byte(cert["certificate"].(string)), []byte(cert["private_key"].(string)), nil } diff --git a/internal/controller/root-ca.go b/internal/controller/root-ca.go index 9b1b025..8594c07 100644 --- a/internal/controller/root-ca.go +++ b/internal/controller/root-ca.go @@ -11,6 +11,7 @@ func (s *controller) rootCA(i RootCA) { if err != nil { zap.L().Warn( "existing root-ca", + zap.String("common_name", i.CommonName), zap.Error(err), ) } @@ -21,6 +22,7 @@ func (s *controller) rootCA(i RootCA) { if err := s.generateRootCA(i); err != nil { zap.L().Error( "generate root-ca", + zap.String("common_name", i.CommonName), zap.Error(err), ) return diff --git a/internal/controller/rsa.go b/internal/controller/rsa.go index cafec0f..dfd68b6 100644 --- a/internal/controller/rsa.go +++ b/internal/controller/rsa.go @@ -6,22 +6,47 @@ import ( "crypto/x509" "encoding/pem" "fmt" - "path" "go.uber.org/zap" ) func (s *controller) rsa(i RSA) { - crt, key, err := s.generateRSA() + private, public, err := s.readRSA(i) if err != nil { - zap.L().Error("generate csr", zap.Error(err)) + zap.L().Warn( + "read rsa", + zap.String("name", i.Name), + zap.Error(err)) + private, public, err = s.generateRSA() + if err != nil { + zap.L().Error( + "generate rsa", + zap.String("name", i.Name), + zap.Error(err)) + return + } } - if err = s.storeRSA(i, crt, key); err != nil { - zap.L().Error("store csr", zap.Error(err)) + if err = s.storeRSA(i, private, public); err != nil { + zap.L().Error( + "store rsa", + zap.String("name", i.Name), + zap.Error(err), + ) } } +func (s *controller) readRSA(i RSA) (private []byte, public []byte, err error) { + storedRSA, err := s.vault.Get(s.cfg.Keys.VaultKV, i.Name) + if err != nil { + err = fmt.Errorf("get from vault_kv %s : %w", s.cfg.Keys.VaultKV, err) + return + } + + private, public = []byte(storedRSA["certificate"].(string)), []byte(storedRSA["private_key"].(string)) + return +} + func (s *controller) generateRSA() (private []byte, public []byte, err error) { privateKey, err := rsa.GenerateKey(rand.Reader, 4096) if err != nil { @@ -49,8 +74,8 @@ func (s *controller) storeRSA(i RSA, private, public []byte) error { "private": string(private), "public": string(public), } - _, name := path.Split(i.HostPath) - if err := s.vault.Put(s.cfg.Keys.VaultKV, name, storedRSA); err != nil { + + if err := s.vault.Put(s.cfg.Keys.VaultKV, i.Name, storedRSA); err != nil { return fmt.Errorf("saving in vault: %w", err) } From f5c2f1b32aefda7a2d33a9b474824847e4151117 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 23 Jun 2022 19:47:48 +0300 Subject: [PATCH 072/220] up --- internal/controller/rsa.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/internal/controller/rsa.go b/internal/controller/rsa.go index dfd68b6..bdbd7be 100644 --- a/internal/controller/rsa.go +++ b/internal/controller/rsa.go @@ -16,13 +16,15 @@ func (s *controller) rsa(i RSA) { zap.L().Warn( "read rsa", zap.String("name", i.Name), - zap.Error(err)) + zap.Error(err), + ) private, public, err = s.generateRSA() if err != nil { zap.L().Error( "generate rsa", zap.String("name", i.Name), - zap.Error(err)) + zap.Error(err), + ) return } } From f8f1e42fb913be56a6f74c25db91fe9be476742f Mon Sep 17 00:00:00 2001 From: irbgeo Date: Wed, 29 Jun 2022 14:34:14 +0300 Subject: [PATCH 073/220] up name --- cmd/key-keeper/main.go | 6 +++--- go.mod | 2 +- internal/config/config.go | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/key-keeper/main.go b/cmd/key-keeper/main.go index fca39e8..d0ff62a 100644 --- a/cmd/key-keeper/main.go +++ b/cmd/key-keeper/main.go @@ -8,9 +8,9 @@ import ( "go.uber.org/zap" - "github.com/terra-cube/key-keeper/internal/config" - "github.com/terra-cube/key-keeper/internal/controller" - "github.com/terra-cube/key-keeper/internal/vault" + "github.com/fraima/key-keeper/internal/config" + "github.com/fraima/key-keeper/internal/controller" + "github.com/fraima/key-keeper/internal/vault" ) func main() { diff --git a/go.mod b/go.mod index 62aade3..3ae6e28 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/terra-cube/key-keeper +module github.com/fraima/key-keeper go 1.18 diff --git a/internal/config/config.go b/internal/config/config.go index bdf0860..c2287c0 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -6,8 +6,8 @@ import ( "gopkg.in/yaml.v3" - "github.com/terra-cube/key-keeper/internal/controller" - "github.com/terra-cube/key-keeper/internal/vault" + "github.com/fraima/key-keeper/internal/controller" + "github.com/fraima/key-keeper/internal/vault" ) type Config struct { From 63aea4bd58f913ad643ce55faa9275f6dd6433ca Mon Sep 17 00:00:00 2001 From: irbgeo Date: Wed, 29 Jun 2022 14:46:04 +0300 Subject: [PATCH 074/220] update --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 523a435..4d2ede5 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,13 @@ # key-keeper +Build: + + go build -o key-keeper cmd/key-keeper/main.go + +Run: + + key-keeper -config /path/to/config + Example config.yml ```yaml @@ -46,11 +54,3 @@ keys: rsa: - host_path: "" ``` - -Build: - - go build -o key-keeper cmd/key-keeper/main.go - -Run: - - key-keeper -config /path/to/config From e56f5819460e194d62f7c70977800a856d731bd5 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Wed, 29 Jun 2022 15:08:35 +0300 Subject: [PATCH 075/220] update --- internal/controller/csr.go | 3 ++- internal/controller/intermediate-ca-exported-key.go | 3 ++- internal/controller/intermediate-ca.go | 5 +++-- internal/controller/root-ca.go | 5 +++-- internal/vault/vault.go | 5 +++-- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/internal/controller/csr.go b/internal/controller/csr.go index d057e6e..3df0729 100644 --- a/internal/controller/csr.go +++ b/internal/controller/csr.go @@ -3,6 +3,7 @@ package controller import ( "fmt" "os" + "path" "strings" "time" @@ -44,7 +45,7 @@ func (s *controller) generateCSR(i CSR) ([]byte, []byte, error) { "alt_names": strings.Join(i.Hosts, ","), "ip_sans": strings.Join(i.IPs, ","), } - path := i.CertPath + "/issue/" + i.Role + path := path.Join(i.CertPath, "issue", i.Role) cert, err := s.vault.Write(path, certData) if err != nil { return nil, nil, fmt.Errorf("generate with path %s : %w", path, err) diff --git a/internal/controller/intermediate-ca-exported-key.go b/internal/controller/intermediate-ca-exported-key.go index 89d7c5d..8c7e1d3 100644 --- a/internal/controller/intermediate-ca-exported-key.go +++ b/internal/controller/intermediate-ca-exported-key.go @@ -3,6 +3,7 @@ package controller import ( "crypto/tls" "fmt" + "path" "time" "go.uber.org/zap" @@ -70,7 +71,7 @@ func (s *controller) generateIntermediateCAWithExportedKey(i IntermediateCA) (cr "ttl": "8760h", } - path := i.CertPath + "/intermediate/generate/exported" + path := path.Join(i.CertPath, "intermediate/generate/exported") csr, err := s.vault.Write(path, csrData) if err != nil { err = fmt.Errorf("create: %w", err) diff --git a/internal/controller/intermediate-ca.go b/internal/controller/intermediate-ca.go index 97e4185..9cb959c 100644 --- a/internal/controller/intermediate-ca.go +++ b/internal/controller/intermediate-ca.go @@ -2,6 +2,7 @@ package controller import ( "fmt" + "path" "go.uber.org/zap" ) @@ -44,7 +45,7 @@ func (s *controller) intermediateCA(i IntermediateCA) { } func (s *controller) readIntermediateCA(i IntermediateCA) (crt []byte, err error) { - path := i.CertPath + "/cert/ca_chain" + path := path.Join(i.CertPath, "cert/ca_chain") ica, err := s.vault.Read(path) if ica != nil { return []byte(ica["certificate"].(string)), err @@ -59,7 +60,7 @@ func (s *controller) generateIntermediateCA(i IntermediateCA) (crt []byte, err e "ttl": "8760h", } - path := i.CertPath + "/intermediate/generate/internal" + path := path.Join(i.CertPath, "intermediate/generate/internal") csr, err := s.vault.Write(path, csrData) if err != nil { err = fmt.Errorf("create intermediate CA: %w", err) diff --git a/internal/controller/root-ca.go b/internal/controller/root-ca.go index 8594c07..77929e4 100644 --- a/internal/controller/root-ca.go +++ b/internal/controller/root-ca.go @@ -2,6 +2,7 @@ package controller import ( "fmt" + "path" "go.uber.org/zap" ) @@ -31,7 +32,7 @@ func (s *controller) rootCA(i RootCA) { } func (s *controller) isExistRootCA(i RootCA) (bool, error) { - path := i.RootPathCA + "/cert/ca" + path := path.Join(i.RootPathCA, "cert/ca") rootCA, err := s.vault.Read(path) if err != nil { err = fmt.Errorf("read root CA: %w", err) @@ -44,7 +45,7 @@ func (s *controller) generateRootCA(i RootCA) error { "common_name": i.CommonName, "ttl": "8760h", } - path := i.RootPathCA + "/root/generate/internal" + path := path.Join(i.RootPathCA, "root/generate/internal") _, err := s.vault.Write(path, rootCAData) if err != nil { err = fmt.Errorf("create root CA: %w", err) diff --git a/internal/vault/vault.go b/internal/vault/vault.go index 511a319..1188b82 100644 --- a/internal/vault/vault.go +++ b/internal/vault/vault.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/http" + "path" "github.com/hashicorp/vault/api" auth "github.com/hashicorp/vault/api/auth/approle" @@ -62,7 +63,7 @@ func New(cfg Config) (*vault, error) { } func (s *vault) roleID(cfg Config) (string, error) { - path := fmt.Sprintf("auth/%s/role/%s/role-id", cfg.AppRolePath, cfg.AppRoleName) + path := path.Join("auth", cfg.AppRolePath, "role", cfg.AppRoleName, "role-id") approle, err := s.Read(path) if err != nil { if roleID, rErr := readFromFile(cfg.LocalPathToRoleID); rErr == nil { @@ -85,7 +86,7 @@ func (s *vault) roleID(cfg Config) (string, error) { } func (s *vault) secretID(cfg Config) (string, error) { - path := fmt.Sprintf("auth/%s/role/%s/secret-id", cfg.AppRolePath, cfg.AppRoleName) + path := path.Join("auth", cfg.AppRolePath, "role", cfg.AppRoleName, "secret-id") approle, err := s.Write(path, nil) if err != nil { if secretID, rErr := readFromFile(cfg.LocalPathToSecretID); rErr == nil { From f04521ee6965cf339a3492e9f3a452dc3f5ec602 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Sat, 2 Jul 2022 13:29:25 +0300 Subject: [PATCH 076/220] add logs --- internal/controller/controller.go | 2 +- internal/controller/rsa.go | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 501ab89..2077332 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -80,7 +80,7 @@ func (s *controller) workflow() { zap.L().Debug("key-rsa") for _, k := range s.cfg.Keys.RSA { go func(k RSA) { - s.rsa(k) + s.Rsa(k) }(k) } diff --git a/internal/controller/rsa.go b/internal/controller/rsa.go index bdbd7be..c2bc6be 100644 --- a/internal/controller/rsa.go +++ b/internal/controller/rsa.go @@ -10,7 +10,7 @@ import ( "go.uber.org/zap" ) -func (s *controller) rsa(i RSA) { +func (s *controller) Rsa(i RSA) { private, public, err := s.readRSA(i) if err != nil { zap.L().Warn( @@ -27,6 +27,9 @@ func (s *controller) rsa(i RSA) { ) return } + zap.L().Debug("rsa is created", zap.String("name", i.Name)) + } else { + zap.L().Debug("rsa is read", zap.String("name", i.Name)) } if err = s.storeRSA(i, private, public); err != nil { @@ -35,6 +38,8 @@ func (s *controller) rsa(i RSA) { zap.String("name", i.Name), zap.Error(err), ) + } else { + zap.L().Debug("rsa is stored", zap.String("name", i.Name)) } } From 126d0badbd34c1bb65f3c4dcd159ff887434d60b Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 5 Jul 2022 11:48:47 +0300 Subject: [PATCH 077/220] update --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4d2ede5..ae1e16e 100644 --- a/README.md +++ b/README.md @@ -52,5 +52,6 @@ keys: vault_kv: "" rsa: + - name: "" - host_path: "" ``` From f7fa1b59ab7cf934a0324c8eca18bbbfc4591a4b Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 5 Jul 2022 14:13:55 +0300 Subject: [PATCH 078/220] up --- internal/controller/controller.go | 2 +- internal/controller/rsa.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 2077332..501ab89 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -80,7 +80,7 @@ func (s *controller) workflow() { zap.L().Debug("key-rsa") for _, k := range s.cfg.Keys.RSA { go func(k RSA) { - s.Rsa(k) + s.rsa(k) }(k) } diff --git a/internal/controller/rsa.go b/internal/controller/rsa.go index c2bc6be..4d477b8 100644 --- a/internal/controller/rsa.go +++ b/internal/controller/rsa.go @@ -10,7 +10,7 @@ import ( "go.uber.org/zap" ) -func (s *controller) Rsa(i RSA) { +func (s *controller) rsa(i RSA) { private, public, err := s.readRSA(i) if err != nil { zap.L().Warn( @@ -50,7 +50,7 @@ func (s *controller) readRSA(i RSA) (private []byte, public []byte, err error) { return } - private, public = []byte(storedRSA["certificate"].(string)), []byte(storedRSA["private_key"].(string)) + private, public = []byte(storedRSA["private"].(string)), []byte(storedRSA["public"].(string)) return } From e5c6a7e176fc755df14499e8675e5b70d7dfe142 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 5 Jul 2022 14:24:23 +0300 Subject: [PATCH 079/220] update --- internal/controller/rsa.go | 39 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/internal/controller/rsa.go b/internal/controller/rsa.go index 4d477b8..c6fbb55 100644 --- a/internal/controller/rsa.go +++ b/internal/controller/rsa.go @@ -28,19 +28,34 @@ func (s *controller) rsa(i RSA) { return } zap.L().Debug("rsa is created", zap.String("name", i.Name)) + storedRSA := map[string]interface{}{ + "private": string(private), + "public": string(public), + } + + if err := s.vault.Put(s.cfg.Keys.VaultKV, i.Name, storedRSA); err != nil { + zap.L().Error( + "store rsa in kv", + zap.String("name", i.Name), + zap.String("kv", s.cfg.Keys.VaultKV), + zap.Error(err), + ) + return + } } else { zap.L().Debug("rsa is read", zap.String("name", i.Name)) } - if err = s.storeRSA(i, private, public); err != nil { + if err := s.storeKey(i.HostPath, private, public); err != nil { zap.L().Error( - "store rsa", + "store rsa in host", zap.String("name", i.Name), + zap.String("path", i.HostPath), zap.Error(err), ) - } else { - zap.L().Debug("rsa is stored", zap.String("name", i.Name)) + return } + zap.L().Debug("rsa is stored", zap.String("name", i.Name)) } func (s *controller) readRSA(i RSA) (private []byte, public []byte, err error) { @@ -75,19 +90,3 @@ func (s *controller) generateRSA() (private []byte, public []byte, err error) { ) return } - -func (s *controller) storeRSA(i RSA, private, public []byte) error { - storedRSA := map[string]interface{}{ - "private": string(private), - "public": string(public), - } - - if err := s.vault.Put(s.cfg.Keys.VaultKV, i.Name, storedRSA); err != nil { - return fmt.Errorf("saving in vault: %w", err) - } - - if err := s.storeKey(i.HostPath, private, public); err != nil { - return fmt.Errorf("host path %s : %w", i.HostPath, err) - } - return nil -} From 56cfa768e6826b690ca91b3843c93527d1184193 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 5 Jul 2022 17:41:27 +0300 Subject: [PATCH 080/220] rsa type --- internal/controller/rsa.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/controller/rsa.go b/internal/controller/rsa.go index c6fbb55..febd8ec 100644 --- a/internal/controller/rsa.go +++ b/internal/controller/rsa.go @@ -77,14 +77,14 @@ func (s *controller) generateRSA() (private []byte, public []byte, err error) { private = pem.EncodeToMemory( &pem.Block{ - Type: "RSA PRIVATE KEY", + Type: "PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey), }, ) public = pem.EncodeToMemory( &pem.Block{ - Type: "RSA PUBLIC KEY", + Type: "PUBLIC KEY", Bytes: x509.MarshalPKCS1PublicKey(privateKey.Public().(*rsa.PublicKey)), }, ) From 4a077c5bd9d8e001c962ce92b63e1691c5ad6cd4 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Wed, 6 Jul 2022 12:36:53 +0300 Subject: [PATCH 081/220] update generation --- internal/controller/rsa.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/internal/controller/rsa.go b/internal/controller/rsa.go index febd8ec..9ca6502 100644 --- a/internal/controller/rsa.go +++ b/internal/controller/rsa.go @@ -18,7 +18,7 @@ func (s *controller) rsa(i RSA) { zap.String("name", i.Name), zap.Error(err), ) - private, public, err = s.generateRSA() + private, public, err = s.GenerateRSA() if err != nil { zap.L().Error( "generate rsa", @@ -69,8 +69,8 @@ func (s *controller) readRSA(i RSA) (private []byte, public []byte, err error) { return } -func (s *controller) generateRSA() (private []byte, public []byte, err error) { - privateKey, err := rsa.GenerateKey(rand.Reader, 4096) +func (s *controller) GenerateRSA() (private []byte, public []byte, err error) { + privKey, err := rsa.GenerateKey(rand.Reader, 4096) if err != nil { return } @@ -78,14 +78,18 @@ func (s *controller) generateRSA() (private []byte, public []byte, err error) { private = pem.EncodeToMemory( &pem.Block{ Type: "PRIVATE KEY", - Bytes: x509.MarshalPKCS1PrivateKey(privateKey), + Bytes: x509.MarshalPKCS1PrivateKey(privKey), }, ) + publicKeyBytes, err := x509.MarshalPKIXPublicKey(&privKey.PublicKey) + if err != nil { + return + } public = pem.EncodeToMemory( &pem.Block{ Type: "PUBLIC KEY", - Bytes: x509.MarshalPKCS1PublicKey(privateKey.Public().(*rsa.PublicKey)), + Bytes: publicKeyBytes, }, ) return From f5db71d5ba95b686fca8db240f7dc1cfb52a7dcf Mon Sep 17 00:00:00 2001 From: irbgeo Date: Wed, 6 Jul 2022 13:40:29 +0300 Subject: [PATCH 082/220] update --- internal/controller/rsa.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/controller/rsa.go b/internal/controller/rsa.go index 9ca6502..1a35944 100644 --- a/internal/controller/rsa.go +++ b/internal/controller/rsa.go @@ -77,7 +77,7 @@ func (s *controller) GenerateRSA() (private []byte, public []byte, err error) { private = pem.EncodeToMemory( &pem.Block{ - Type: "PRIVATE KEY", + Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privKey), }, ) From 2eb02e3d1e431508f3c303b42409be872410863e Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 12 Jul 2022 13:45:11 +0300 Subject: [PATCH 083/220] update --- .release | 1 + Dockerfile | 20 ++++++++++++++++++++ Makefile | 6 ++++++ cmd/key-keeper/main.go | 6 +++++- 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 .release create mode 100644 Dockerfile create mode 100644 Makefile diff --git a/.release b/.release new file mode 100644 index 0000000..60453e6 --- /dev/null +++ b/.release @@ -0,0 +1 @@ +v1.0.0 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a798fd1 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,20 @@ +FROM golang:1.18.3-alpine3.16 as builder + +WORKDIR /app + +COPY go.mod . +COPY go.sum . +RUN go mod download +COPY . . + +ARG VERSION + +RUN go install -ldflags "-s \ + -X main.Version=${VERSION}" \ + /app/cmd/key-keeper + +FROM alpine:3.15.0 + +COPY --from=builder /go/bin/key-keeper /usr/local/bin/key-keeper + +ENTRYPOINT ["/usr/local/bin/key-keeper"] \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..323cdce --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +release = $(shell cat .release) +tag = $(DOCKER_USER)/key-keeper:$(release) + +build-and-push: + docker build -t $(tag) --build-arg VERSION=$(release) -f Dockerfile . + docker image push $(tag) \ No newline at end of file diff --git a/cmd/key-keeper/main.go b/cmd/key-keeper/main.go index d0ff62a..2756a8f 100644 --- a/cmd/key-keeper/main.go +++ b/cmd/key-keeper/main.go @@ -13,6 +13,10 @@ import ( "github.com/fraima/key-keeper/internal/vault" ) +var ( + Version = "undefined" +) + func main() { loggerConfig := zap.NewProductionConfig() loggerConfig.Level.SetLevel(zap.DebugLevel) @@ -35,7 +39,7 @@ func main() { zap.L().Fatal("read configuration", zap.Error(err)) } - zap.L().Debug("configuration", zap.Any("config", cfg)) + zap.L().Debug("configuration", zap.Any("config", cfg), zap.String("version", Version)) v, err := vault.New( cfg.Vault, From 975c2a960a1a5750cd8df51496133adaf572d394 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 12 Jul 2022 13:53:52 +0300 Subject: [PATCH 084/220] update --- README.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ae1e16e..4b9e980 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,24 @@ # key-keeper -Build: +## BUILD & PUSH IMAGE - go build -o key-keeper cmd/key-keeper/main.go +Поменять версию релиза в .release и выполнить: -Run: +```bash +make build-and-push DOCKER_USER=geoirb +``` + +# BUILD BIN + +```bash +go build -o key-keeper cmd/key-keeper/main.go +``` + +# RUN BIN - key-keeper -config /path/to/config +```bash +key-keeper -config /path/to/config +``` Example config.yml From 2e08eda28dfd22bfcf9e75f4f045f98351a7f998 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 12 Jul 2022 13:55:27 +0300 Subject: [PATCH 085/220] up readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4b9e980..3fbe3ee 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # key-keeper -## BUILD & PUSH IMAGE +## Build & Push image Поменять версию релиза в .release и выполнить: @@ -8,13 +8,13 @@ make build-and-push DOCKER_USER=geoirb ``` -# BUILD BIN +# Build bin ```bash go build -o key-keeper cmd/key-keeper/main.go ``` -# RUN BIN +# Run bim ```bash key-keeper -config /path/to/config From 04c346ac5ce7f5318df4e83ecd5b5f3c5185f270 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 16 Aug 2022 16:15:57 +0300 Subject: [PATCH 086/220] update --- go.mod | 5 +++-- go.sum | 9 ++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 3ae6e28..cfda956 100644 --- a/go.mod +++ b/go.mod @@ -44,12 +44,13 @@ require ( github.com/oklog/run v1.0.0 // indirect github.com/pierrec/lz4 v2.5.2+incompatible // indirect github.com/ryanuber/go-glob v1.0.0 // indirect + github.com/stretchr/objx v0.2.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.6.0 // indirect - golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect + golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect - golang.org/x/text v0.3.3 // indirect + golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 // indirect google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect google.golang.org/grpc v1.41.0 // indirect diff --git a/go.sum b/go.sum index c3b8ef4..7104e31 100644 --- a/go.sum +++ b/go.sum @@ -224,8 +224,9 @@ github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIH github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 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= @@ -248,8 +249,9 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf 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= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -299,8 +301,9 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From 9f4817f97eb615791ed8162665d9281d0f09c5ee Mon Sep 17 00:00:00 2001 From: irbgeo Date: Wed, 17 Aug 2022 14:04:26 +0300 Subject: [PATCH 087/220] update --- README.md | 3 ++- internal/controller/config.go | 1 + internal/controller/csr.go | 12 ++++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3fbe3ee..650ce70 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,6 @@ certificates: # - public and private помещается в KV с наименованием ${COMMON_NAME} vault_kv: "clusters/cluster-1/kv" reissue_interval: "1d" # интервал перевыпуск - за сутки до истечения перевыпустить. (Хардкод - проверяет раз в час) - # Блок Root_CA отвечает за выпуск корневых сертификатов - на выход не получаем ни сертификат ни ключ от него # что бы все сертификаты выпускались только с Intermediate. root_ca: @@ -60,6 +59,8 @@ certificates: role: "base-role" # system_masters_client # Роль в которой прописаны критерии сертификата (usages,access_ip,access_san,etc) host_path: "/etc/kubernetes/pki/certs/kube-apiserver/cert" # Локальный путь, где будет размещен public / private keys cert_path: "clusters/cluster-1/pki/kube-apiserver" # Путь к сейфу Inermediate CA где будет заказан сертификат + trigger: # Триггер выполняемый при обновлении данного csr + - "cmd commands" keys: vault_kv: "" diff --git a/internal/controller/config.go b/internal/controller/config.go index 1246713..16d67b0 100644 --- a/internal/controller/config.go +++ b/internal/controller/config.go @@ -39,6 +39,7 @@ type CSR struct { CertPath string `yaml:"cert_path"` Role string `yaml:"role"` HostPath string `yaml:"host_path"` + Trigger []string `yaml:"trigger"` } type Keys struct { diff --git a/internal/controller/csr.go b/internal/controller/csr.go index 3df0729..4ada5a7 100644 --- a/internal/controller/csr.go +++ b/internal/controller/csr.go @@ -3,6 +3,7 @@ package controller import ( "fmt" "os" + "os/exec" "path" "strings" "time" @@ -36,6 +37,17 @@ func (s *controller) csr(i CSR) { ) return } + + for _, command := range i.Trigger { + cmd := strings.Split(command, " ") + err := exec.Command(cmd[0], cmd[1:]...).Run() + zap.L().Error( + "csr trigger", + zap.String("common_name", i.CommonName), + zap.String("command", command), + zap.Error(err), + ) + } zap.L().Info("csr generated", zap.String("common_name", i.CommonName)) } From d49612154bb8903bec6e597ec27c6f3e5c975d2c Mon Sep 17 00:00:00 2001 From: irbgeo Date: Fri, 19 Aug 2022 18:33:58 +0300 Subject: [PATCH 088/220] multiple configs | trackeing new configs --- Makefile | 6 +- cmd/key-keeper/main.go | 29 ++--- internal/config/config.go | 70 ++++++++++-- internal/controller/config.go | 18 ++- internal/controller/controller.go | 104 +++++++++--------- internal/{controller => resource}/csr.go | 10 +- .../intermediate-ca-exported-key.go | 14 ++- .../intermediate-ca.go | 14 ++- internal/resource/resource.go | 68 ++++++++++++ internal/{controller => resource}/root-ca.go | 10 +- internal/{controller => resource}/rsa.go | 10 +- internal/{controller => resource}/store.go | 8 +- internal/vault/config.go | 16 --- internal/vault/vault.go | 8 +- 14 files changed, 253 insertions(+), 132 deletions(-) rename internal/{controller => resource}/csr.go (85%) rename internal/{controller => resource}/intermediate-ca-exported-key.go (84%) rename internal/{controller => resource}/intermediate-ca.go (80%) create mode 100644 internal/resource/resource.go rename internal/{controller => resource}/root-ca.go (78%) rename internal/{controller => resource}/rsa.go (86%) rename internal/{controller => resource}/store.go (83%) delete mode 100644 internal/vault/config.go diff --git a/Makefile b/Makefile index 323cdce..e27e0d0 100644 --- a/Makefile +++ b/Makefile @@ -3,4 +3,8 @@ tag = $(DOCKER_USER)/key-keeper:$(release) build-and-push: docker build -t $(tag) --build-arg VERSION=$(release) -f Dockerfile . - docker image push $(tag) \ No newline at end of file + docker image push $(tag) + +formatting: + go install github.com/daixiang0/gci@latest + gci write --skip-generated -s standard -s default -s "prefix(github.com/fraima/key-keeper)" . \ No newline at end of file diff --git a/cmd/key-keeper/main.go b/cmd/key-keeper/main.go index 2756a8f..74f1c78 100644 --- a/cmd/key-keeper/main.go +++ b/cmd/key-keeper/main.go @@ -10,6 +10,7 @@ import ( "github.com/fraima/key-keeper/internal/config" "github.com/fraima/key-keeper/internal/controller" + "github.com/fraima/key-keeper/internal/resource" "github.com/fraima/key-keeper/internal/vault" ) @@ -26,38 +27,28 @@ func main() { } zap.ReplaceGlobals(logger) - var configPath string - flag.StringVar(&configPath, "config", "", "path to config file") + var configDir, configNameLayout string + flag.StringVar(&configDir, "config-dir", "", "path to dir with configs") + flag.StringVar(&configDir, "config-regexp", "", "regexp for config names") flag.Parse() - if configPath == "" { + if configDir == "" { zap.L().Fatal("not found config param") } - cfg, err := config.Read(configPath) + cfg, err := config.New(configDir, configNameLayout) if err != nil { zap.L().Fatal("read configuration", zap.Error(err)) } zap.L().Debug("configuration", zap.Any("config", cfg), zap.String("version", Version)) - v, err := vault.New( - cfg.Vault, - ) - if err != nil { - zap.L().Fatal("init vault", zap.Error(err)) - } - cntl := controller.New( - v, - cfg.Controller, + cfg, + vault.Connect, + resource.Preparing, ) - - go func() { - if err := cntl.Start(); err != nil { - zap.L().Fatal("start", zap.Error(err)) - } - }() + go cntl.Start() zap.L().Info("started") diff --git a/internal/config/config.go b/internal/config/config.go index c2287c0..d6d474d 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1,30 +1,76 @@ package config import ( - "fmt" "io/ioutil" + "os" + "path/filepath" + "regexp" + "go.uber.org/zap" "gopkg.in/yaml.v3" "github.com/fraima/key-keeper/internal/controller" - "github.com/fraima/key-keeper/internal/vault" ) -type Config struct { - Vault vault.Config `yaml:"vault"` - Controller controller.Config `yaml:",inline"` +type config struct { + dir string + reg *regexp.Regexp + + oldConfig map[string]struct{} } -// Read config by path. -func Read(path string) (cfg Config, err error) { - data, err := ioutil.ReadFile(path) +func New(configDir, configNameLayout string) (*config, error) { + reg, err := regexp.Compile(configNameLayout) if err != nil { - err = fmt.Errorf("read config file %s: %w", path, err) - return + return nil, err } - if err = yaml.Unmarshal(data, &cfg); err != nil { - err = fmt.Errorf("unmarshal config %w", err) + + return &config{ + dir: configDir, + reg: reg, + + oldConfig: make(map[string]struct{}), + }, nil +} + +// GetNewConfig return new config from config dir. +func (s *config) GetNewConfig() (cfgs []controller.Config, err error) { + list, err := s.getNewConfigFiles() + if err != nil { return } + + for _, path := range list { + data, err := ioutil.ReadFile(path) + if err != nil { + zap.L().Error("read config file", zap.String("path", path), zap.Error(err)) + continue + } + var cfg controller.Config + if err = yaml.Unmarshal(data, cfg); err != nil { + zap.L().Error("unmurshal config file", zap.String("path", path), zap.Error(err)) + continue + } + + cfgs = append(cfgs, cfg) + s.oldConfig[path] = struct{}{} + } + return } + +func (s *config) getNewConfigFiles() ([]string, error) { + var newConfigFiles []string + err := filepath.Walk(s.dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return nil + } + + _, isOld := s.oldConfig[path] + if !isOld && !info.IsDir() && s.reg.Match([]byte(info.Name())) { + newConfigFiles = append(newConfigFiles, path) + } + return nil + }) + return newConfigFiles, err +} diff --git a/internal/controller/config.go b/internal/controller/config.go index 16d67b0..08a73cb 100644 --- a/internal/controller/config.go +++ b/internal/controller/config.go @@ -4,8 +4,24 @@ import ( "time" ) -// Config for work controller. type Config struct { + Vault VaultConfig `yaml:"vault"` + Recource RecourceConfig `yaml:",inline"` +} + +// VaultConfig for work with vault +type VaultConfig struct { + Address string `yaml:"address"` + BootsrapToken string `yaml:"bootstrap_token"` + AppRolePath string `yaml:"approle_path"` + AppRoleName string `yaml:"approle_name"` + LocalPathToRoleID string `yaml:"local_path_to_role_id"` + LocalPathToSecretID string `yaml:"local_path_to_secret_id"` + RequestTimeout time.Duration `yaml:"request_timeout"` +} + +// RecourceConfig for work controller. +type RecourceConfig struct { Certificates Certificates `json:"certificates"` Keys Keys `json:"keys"` } diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 501ab89..0435a09 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -1,87 +1,87 @@ package controller import ( + "fmt" "sync" "time" "go.uber.org/zap" ) -var intermediateCommonNameLayout = "%s Intermediate Authority" +type config interface { + GetNewConfig() (cfgs []Config, err error) +} -type vault interface { +type Vault interface { Write(path string, data map[string]interface{}) (map[string]interface{}, error) Read(path string) (map[string]interface{}, error) Put(mountPath, secretePath string, data map[string]interface{}) error Get(mountPath, secretePath string) (map[string]interface{}, error) } +type Resource interface { + Check() +} + type controller struct { - vault vault + config config + vaultConnector func(cfg VaultConfig) (Vault, error) - cfg Config + resourcePreparing func(vault Vault, cfg RecourceConfig) Resource + lock sync.RWMutex + resources []Resource } -func New(store vault, certs Config) *controller { - c := &controller{ - vault: store, - cfg: certs, +func New( + config config, + vaultConnector func(cfg VaultConfig) (Vault, error), + resourcePreparing func(vault Vault, cfg RecourceConfig) Resource, +) *controller { + return &controller{ + config: config, + vaultConnector: vaultConnector, + resourcePreparing: resourcePreparing, } - return c } // Start controller of key-keeper. -func (s *controller) Start() error { - s.workflow() +func (s *controller) Start() { + go func() { + t := time.NewTicker(30 * time.Second) + defer t.Stop() + for range t.C { + if err := s.getNewRecource(); err != nil { + zap.L().Error("runtime", zap.Error(err)) + } + } + }() t := time.NewTicker(time.Hour) defer t.Stop() for range t.C { - s.workflow() + s.lock.RLock() + for _, r := range s.resources { + r.Check() + } + s.lock.RUnlock() } - - return nil } -func (s *controller) workflow() { - wg := &sync.WaitGroup{} - - zap.L().Debug("certificate-root-ca") - for _, c := range s.cfg.Certificates.RootCA { - wg.Add(1) - go func(c RootCA) { - defer wg.Done() - s.rootCA(c) - }(c) +func (s *controller) getNewRecource() error { + cfgList, err := s.config.GetNewConfig() + if err != nil { + return fmt.Errorf("get new configs: %w", err) } - wg.Wait() - zap.L().Debug("certificate-intermediate-ca") - for _, c := range s.cfg.Certificates.IntermediateCA { - wg.Add(1) - go func(c IntermediateCA) { - defer wg.Done() - if c.ExportedKey { - s.intermediateCAWithExportedKey(c) - } else { - s.intermediateCA(c) - } - }(c) - } - wg.Wait() - - zap.L().Debug("certificate-csr") - for _, c := range s.cfg.Certificates.CSR { - go func(c CSR) { - s.csr(c) - }(c) + for _, cfg := range cfgList { + vaultConnect, err := s.vaultConnector(cfg.Vault) + if err != nil { + zap.L().Error("connect to vault", zap.Error(err)) + } + r := s.resourcePreparing(vaultConnect, cfg.Recource) + s.lock.Lock() + s.resources = append(s.resources, r) + s.lock.Unlock() } - - zap.L().Debug("key-rsa") - for _, k := range s.cfg.Keys.RSA { - go func(k RSA) { - s.rsa(k) - }(k) - } - + return nil } diff --git a/internal/controller/csr.go b/internal/resource/csr.go similarity index 85% rename from internal/controller/csr.go rename to internal/resource/csr.go index 4ada5a7..3cd3644 100644 --- a/internal/controller/csr.go +++ b/internal/resource/csr.go @@ -1,4 +1,4 @@ -package controller +package resource import ( "fmt" @@ -9,9 +9,11 @@ import ( "time" "go.uber.org/zap" + + "github.com/fraima/key-keeper/internal/controller" ) -func (s *controller) csr(i CSR) { +func (s *resource) csr(i controller.CSR) { csr, err := s.readCertificate(i.HostPath) if csr != nil && time.Until(csr.Leaf.NotAfter) > s.cfg.Certificates.ReissueInterval { return @@ -51,7 +53,7 @@ func (s *controller) csr(i CSR) { zap.L().Info("csr generated", zap.String("common_name", i.CommonName)) } -func (s *controller) generateCSR(i CSR) ([]byte, []byte, error) { +func (s *resource) generateCSR(i controller.CSR) ([]byte, []byte, error) { certData := map[string]interface{}{ "common_name": i.CommonName, "alt_names": strings.Join(i.Hosts, ","), @@ -66,7 +68,7 @@ func (s *controller) generateCSR(i CSR) ([]byte, []byte, error) { return []byte(cert["certificate"].(string)), []byte(cert["private_key"].(string)), nil } -func (s *controller) storeCSR(i CSR, cert, key []byte) error { +func (s *resource) storeCSR(i controller.CSR, cert, key []byte) error { if err := s.storeCertificate(i.HostPath, cert, key); err != nil { return fmt.Errorf("host path %s : %w", i.HostPath, err) } diff --git a/internal/controller/intermediate-ca-exported-key.go b/internal/resource/intermediate-ca-exported-key.go similarity index 84% rename from internal/controller/intermediate-ca-exported-key.go rename to internal/resource/intermediate-ca-exported-key.go index 8c7e1d3..1074590 100644 --- a/internal/controller/intermediate-ca-exported-key.go +++ b/internal/resource/intermediate-ca-exported-key.go @@ -1,4 +1,4 @@ -package controller +package resource import ( "crypto/tls" @@ -7,9 +7,11 @@ import ( "time" "go.uber.org/zap" + + "github.com/fraima/key-keeper/internal/controller" ) -func (s *controller) intermediateCAWithExportedKey(i IntermediateCA) { +func (s *resource) intermediateCAWithExportedKey(i controller.IntermediateCA) { var ( crt, key []byte err error @@ -45,7 +47,7 @@ func (s *controller) intermediateCAWithExportedKey(i IntermediateCA) { } } -func (s *controller) readIntermediateCAWithExportedKey(i IntermediateCA) (crt, key []byte, err error) { +func (s *resource) readIntermediateCAWithExportedKey(i controller.IntermediateCA) (crt, key []byte, err error) { storedICA, err := s.vault.Get(s.cfg.Certificates.VaultKV, i.CommonName+"-ca") if err != nil { err = fmt.Errorf("get from vault_kv %s : %w", s.cfg.Certificates.VaultKV, err) @@ -64,10 +66,10 @@ func (s *controller) readIntermediateCAWithExportedKey(i IntermediateCA) (crt, k return } -func (s *controller) generateIntermediateCAWithExportedKey(i IntermediateCA) (crt, key []byte, err error) { +func (s *resource) generateIntermediateCAWithExportedKey(i controller.IntermediateCA) (crt, key []byte, err error) { // create intermediate ca with exported key csrData := map[string]interface{}{ - "common_name": fmt.Sprintf(intermediateCommonNameLayout, i.CommonName), + "common_name": fmt.Sprintf("%s Intermediate Authority", i.CommonName), "ttl": "8760h", } @@ -107,7 +109,7 @@ func (s *controller) generateIntermediateCAWithExportedKey(i IntermediateCA) (cr return []byte(ica["certificate"].(string)), []byte(csr["private_key"].(string)), nil } -func (s *controller) storeIntermediateCAWithExportedKey(i IntermediateCA, crt, key []byte) error { +func (s *resource) storeIntermediateCAWithExportedKey(i controller.IntermediateCA, crt, key []byte) error { // saving the created intermediate ca with exported key storedICA := map[string]interface{}{ "certificate": string(crt), diff --git a/internal/controller/intermediate-ca.go b/internal/resource/intermediate-ca.go similarity index 80% rename from internal/controller/intermediate-ca.go rename to internal/resource/intermediate-ca.go index 9cb959c..5bb1ef4 100644 --- a/internal/controller/intermediate-ca.go +++ b/internal/resource/intermediate-ca.go @@ -1,13 +1,15 @@ -package controller +package resource import ( "fmt" "path" "go.uber.org/zap" + + "github.com/fraima/key-keeper/internal/controller" ) -func (s *controller) intermediateCA(i IntermediateCA) { +func (s *resource) intermediateCA(i controller.IntermediateCA) { var ( crt []byte err error @@ -44,7 +46,7 @@ func (s *controller) intermediateCA(i IntermediateCA) { } } -func (s *controller) readIntermediateCA(i IntermediateCA) (crt []byte, err error) { +func (s *resource) readIntermediateCA(i controller.IntermediateCA) (crt []byte, err error) { path := path.Join(i.CertPath, "cert/ca_chain") ica, err := s.vault.Read(path) if ica != nil { @@ -53,10 +55,10 @@ func (s *controller) readIntermediateCA(i IntermediateCA) (crt []byte, err error return } -func (s *controller) generateIntermediateCA(i IntermediateCA) (crt []byte, err error) { +func (s *resource) generateIntermediateCA(i controller.IntermediateCA) (crt []byte, err error) { // create intermediate CA csrData := map[string]interface{}{ - "common_name": fmt.Sprintf(intermediateCommonNameLayout, i.CommonName), + "common_name": fmt.Sprintf("%s Intermediate Authority", i.CommonName), "ttl": "8760h", } @@ -96,7 +98,7 @@ func (s *controller) generateIntermediateCA(i IntermediateCA) (crt []byte, err e return []byte(ica["certificate"].(string)), nil } -func (s *controller) storeIntermediateCA(i IntermediateCA, crt, key []byte) error { +func (s *resource) storeIntermediateCA(i controller.IntermediateCA, crt, key []byte) error { if err := s.storeCertificate(i.HostPath, crt, key); err != nil { return fmt.Errorf("host path %s : %w", i.HostPath, err) } diff --git a/internal/resource/resource.go b/internal/resource/resource.go new file mode 100644 index 0000000..0381678 --- /dev/null +++ b/internal/resource/resource.go @@ -0,0 +1,68 @@ +package resource + +import ( + "sync" + + "go.uber.org/zap" + + "github.com/fraima/key-keeper/internal/controller" +) + +type resource struct { + vault controller.Vault + cfg controller.RecourceConfig +} + +func Preparing( + vault controller.Vault, + cfg controller.RecourceConfig, +) controller.Resource { + r := &resource{ + vault: vault, + cfg: cfg, + } + r.Check() + return r +} + +func (s *resource) Check() { + wg := &sync.WaitGroup{} + + zap.L().Debug("certificate-root-ca") + for _, c := range s.cfg.Certificates.RootCA { + wg.Add(1) + go func(c controller.RootCA) { + defer wg.Done() + s.rootCA(c) + }(c) + } + wg.Wait() + + zap.L().Debug("certificate-intermediate-ca") + for _, c := range s.cfg.Certificates.IntermediateCA { + wg.Add(1) + go func(c controller.IntermediateCA) { + defer wg.Done() + if c.ExportedKey { + s.intermediateCAWithExportedKey(c) + } else { + s.intermediateCA(c) + } + }(c) + } + wg.Wait() + + zap.L().Debug("certificate-csr") + for _, c := range s.cfg.Certificates.CSR { + go func(c controller.CSR) { + s.csr(c) + }(c) + } + + zap.L().Debug("key-rsa") + for _, k := range s.cfg.Keys.RSA { + go func(k controller.RSA) { + s.rsa(k) + }(k) + } +} diff --git a/internal/controller/root-ca.go b/internal/resource/root-ca.go similarity index 78% rename from internal/controller/root-ca.go rename to internal/resource/root-ca.go index 77929e4..4b3f6d7 100644 --- a/internal/controller/root-ca.go +++ b/internal/resource/root-ca.go @@ -1,13 +1,15 @@ -package controller +package resource import ( "fmt" "path" "go.uber.org/zap" + + "github.com/fraima/key-keeper/internal/controller" ) -func (s *controller) rootCA(i RootCA) { +func (s *resource) rootCA(i controller.RootCA) { isExist, err := s.isExistRootCA(i) if err != nil { zap.L().Warn( @@ -31,7 +33,7 @@ func (s *controller) rootCA(i RootCA) { zap.L().Info("root-ca generated", zap.String("common_name", i.CommonName)) } -func (s *controller) isExistRootCA(i RootCA) (bool, error) { +func (s *resource) isExistRootCA(i controller.RootCA) (bool, error) { path := path.Join(i.RootPathCA, "cert/ca") rootCA, err := s.vault.Read(path) if err != nil { @@ -40,7 +42,7 @@ func (s *controller) isExistRootCA(i RootCA) (bool, error) { return rootCA != nil, err } -func (s *controller) generateRootCA(i RootCA) error { +func (s *resource) generateRootCA(i controller.RootCA) error { rootCAData := map[string]interface{}{ "common_name": i.CommonName, "ttl": "8760h", diff --git a/internal/controller/rsa.go b/internal/resource/rsa.go similarity index 86% rename from internal/controller/rsa.go rename to internal/resource/rsa.go index 1a35944..dd08bc1 100644 --- a/internal/controller/rsa.go +++ b/internal/resource/rsa.go @@ -1,4 +1,4 @@ -package controller +package resource import ( "crypto/rand" @@ -8,9 +8,11 @@ import ( "fmt" "go.uber.org/zap" + + "github.com/fraima/key-keeper/internal/controller" ) -func (s *controller) rsa(i RSA) { +func (s *resource) rsa(i controller.RSA) { private, public, err := s.readRSA(i) if err != nil { zap.L().Warn( @@ -58,7 +60,7 @@ func (s *controller) rsa(i RSA) { zap.L().Debug("rsa is stored", zap.String("name", i.Name)) } -func (s *controller) readRSA(i RSA) (private []byte, public []byte, err error) { +func (s *resource) readRSA(i controller.RSA) (private []byte, public []byte, err error) { storedRSA, err := s.vault.Get(s.cfg.Keys.VaultKV, i.Name) if err != nil { err = fmt.Errorf("get from vault_kv %s : %w", s.cfg.Keys.VaultKV, err) @@ -69,7 +71,7 @@ func (s *controller) readRSA(i RSA) (private []byte, public []byte, err error) { return } -func (s *controller) GenerateRSA() (private []byte, public []byte, err error) { +func (s *resource) GenerateRSA() (private []byte, public []byte, err error) { privKey, err := rsa.GenerateKey(rand.Reader, 4096) if err != nil { return diff --git a/internal/controller/store.go b/internal/resource/store.go similarity index 83% rename from internal/controller/store.go rename to internal/resource/store.go index 3f85a3f..606e11a 100644 --- a/internal/controller/store.go +++ b/internal/resource/store.go @@ -1,4 +1,4 @@ -package controller +package resource import ( "crypto/tls" @@ -7,7 +7,7 @@ import ( "os" ) -func (s *controller) storeKey(path string, privare, public []byte) error { +func (s *resource) storeKey(path string, privare, public []byte) error { if err := os.WriteFile(path+".pem", privare, 0600); err != nil { return fmt.Errorf("failed to save privare key with path %s: %w", path, err) } @@ -18,7 +18,7 @@ func (s *controller) storeKey(path string, privare, public []byte) error { return nil } -func (s *controller) storeCertificate(path string, crt, key []byte) error { +func (s *resource) storeCertificate(path string, crt, key []byte) error { if crt != nil { if err := os.WriteFile(path+".pem", crt, 0644); err != nil { return fmt.Errorf("failed to save certificate with path %s: %w", path, err) @@ -33,7 +33,7 @@ func (s *controller) storeCertificate(path string, crt, key []byte) error { return nil } -func (s *controller) readCertificate(path string) (*tls.Certificate, error) { +func (s *resource) readCertificate(path string) (*tls.Certificate, error) { crt, err := os.ReadFile(path + ".pem") if err != nil { return nil, err diff --git a/internal/vault/config.go b/internal/vault/config.go deleted file mode 100644 index 77185c6..0000000 --- a/internal/vault/config.go +++ /dev/null @@ -1,16 +0,0 @@ -package vault - -import ( - "time" -) - -// Config for work with vault -type Config struct { - Address string `yaml:"address"` - BootsrapToken string `yaml:"bootstrap_token"` - AppRolePath string `yaml:"approle_path"` - AppRoleName string `yaml:"approle_name"` - LocalPathToRoleID string `yaml:"local_path_to_role_id"` - LocalPathToSecretID string `yaml:"local_path_to_secret_id"` - RequestTimeout time.Duration `yaml:"request_timeout"` -} diff --git a/internal/vault/vault.go b/internal/vault/vault.go index 1188b82..72a8759 100644 --- a/internal/vault/vault.go +++ b/internal/vault/vault.go @@ -8,13 +8,15 @@ import ( "github.com/hashicorp/vault/api" auth "github.com/hashicorp/vault/api/auth/approle" + + "github.com/fraima/key-keeper/internal/controller" ) type vault struct { cli *api.Client } -func New(cfg Config) (*vault, error) { +func Connect(cfg controller.VaultConfig) (controller.Vault, error) { client, err := api.NewClient( &api.Config{ Address: cfg.Address, @@ -62,7 +64,7 @@ func New(cfg Config) (*vault, error) { return s, nil } -func (s *vault) roleID(cfg Config) (string, error) { +func (s *vault) roleID(cfg controller.VaultConfig) (string, error) { path := path.Join("auth", cfg.AppRolePath, "role", cfg.AppRoleName, "role-id") approle, err := s.Read(path) if err != nil { @@ -85,7 +87,7 @@ func (s *vault) roleID(cfg Config) (string, error) { return roleID.(string), err } -func (s *vault) secretID(cfg Config) (string, error) { +func (s *vault) secretID(cfg controller.VaultConfig) (string, error) { path := path.Join("auth", cfg.AppRolePath, "role", cfg.AppRoleName, "secret-id") approle, err := s.Write(path, nil) if err != nil { From 4cd96ee1d3ea0ca87e80c8178eeff95bf20de653 Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Sat, 20 Aug 2022 17:18:20 +0300 Subject: [PATCH 089/220] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D0=B5=D1=82=20=D1=82=D0=B5=D1=81=D1=82=D0=BE=D0=B2=D1=8B?= =?UTF-8?q?=D0=B9=20=D0=BF=D1=80=D0=B8=D0=BC=D0=B5=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test.example.yaml | 106 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 test.example.yaml diff --git a/test.example.yaml b/test.example.yaml new file mode 100644 index 0000000..e79570a --- /dev/null +++ b/test.example.yaml @@ -0,0 +1,106 @@ +--- +global: + vault: + serever: "http://${VAULT_IP}" # rename $address + caBundle: "" # new (сертификат для подключения к волту - при http не должен фигурировать) + tlsInsecure: true # new при указании тру скипать ssl верификацию + auth: + bootstrap: + tokenPath: "" # rename $bootstrap_token + appRole: + name: test-role # rename $approle_name + path: clusters/cluster-1/approle # rename $approle_path + roleIdPath: "$PATH" # rename $local_path_to_role_id + secretIdPath: "$PATH" # rename $local_path_to_secret_id + kv: "clusters/${cluster_name}/kv" + +issuers: + - name: kube-apiserver-server + vault: # Все переменные global.Vault.* могут быть переопределены тут в блоке vault + path: "clusters/cluster-1/pki/kube-apiserver" # альтернатива блоку csr[*].cert_path + role: "system_masters_client" # альтернатива блоку csr[*].role + serever: "http://${VAULT_IP}" # rename $address + caBundle: "" # new (сертификат для подключения к волту - при http не должен фигурировать) + tlsInsecure: true # new при указании тру скипать ssl верификацию + auth: + bootstrap: + tokenPath: "" # rename $bootstrap_token + appRole: + name: test-role # rename $approle_name + path: clusters/cluster-1/approle # rename $approle_path + roleIdPath: "$PATH" # rename $local_path_to_role_id + secretIdPath: "$PATH" # rename $local_path_to_secret_id + + - name: kube-apiserver-ca + vault: # Все переменные global.Vault.* могут быть переопределены тут в блоке vault + intermediate: # Альтернатива блоку certificates.intermediate_ca + path: "clusters/cluster-1/pki/kube-apiserver" # альтернатива блоку csr[*].cert_path + rootPath: "clusters/cluster-1/pki/root" + exportedKey: false + generate: false + +certificates: + - name: kube-apiserver-server + spec: + duration: 2160h # на какой промежуток времени заказывается сертификат + renewBefore: 360h # за сколько до истечения надо перевыпустить + subject: # https://www.vaultproject.io/api-docs/secret/pki + # vault write pki/issue/example_role organization="example.inc" ou="development team" country="EX" + organizations: + - system:masters + ous: [] + countrys: [] + commonName: kube-apiserver-server + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 2048 + usages: + - server auth + - client auth + dnsNames: + - kube-apiserver-server + - www.example.com + ipAddresses: + - 127.0.0.1 + issuerRef: + name: kube-apiserver-server + + hostPathCert: "/etc/kubernetes/pki/certs/kube-apiserver/cert" + trigger: + - systemctl stop kube-apiserver.service + httpCheck: 127.0.0.1:6443 + + - name: kube-apiserver-ca + spec: + duration: 2160h # на какой промежуток времени заказывается сертификат + renewBefore: 360h # за сколько до истечения надо перевыпустить + subject: # https://www.vaultproject.io/api-docs/secret/pki + # vault write pki/issue/example_role organization="example.inc" ou="development team" country="EX" + organizations: [] + ous: [] + countrys: [] + commonName: kube-apiserver-ca + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 2048 + isCa: true + issuerRef: + name: kube-apiserver-ca + + hostPathCert: "/etc/kubernetes/pki/ca" + trigger: + - systemctl stop kube-apiserver.service + httpCheck: 127.0.0.1:6443 + +keys: + - name: system:kube-apiserver-sa + host_path: /etc/kubernetes/pki/certs/kube-apiserver/ # join(host_path,name) + privateKey: # добавить возможность менять тип и сайз + algorithm: RSA + encoding: PKCS1 + size: 2048 + public: true # если false генерил локально, true генерил локально и пушил в vault + vault: + kv: "clusters/${cluster_name}/kv" From 20d90fd3c892b74482f69257a093ae332cf61c91 Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Sat, 20 Aug 2022 18:31:14 +0300 Subject: [PATCH 090/220] =?UTF-8?q?=D0=B4=D0=BE=D0=BF=20=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test.example.yaml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/test.example.yaml b/test.example.yaml index e79570a..2e2957c 100644 --- a/test.example.yaml +++ b/test.example.yaml @@ -17,8 +17,9 @@ global: issuers: - name: kube-apiserver-server vault: # Все переменные global.Vault.* могут быть переопределены тут в блоке vault - path: "clusters/cluster-1/pki/kube-apiserver" # альтернатива блоку csr[*].cert_path - role: "system_masters_client" # альтернатива блоку csr[*].role + role: + name: "system_masters_client" # альтернатива блоку csr[*].role + path: "clusters/cluster-1/pki/kube-apiserver" # альтернатива блоку csr[*].cert_path serever: "http://${VAULT_IP}" # rename $address caBundle: "" # new (сертификат для подключения к волту - при http не должен фигурировать) tlsInsecure: true # new при указании тру скипать ssl верификацию @@ -33,11 +34,13 @@ issuers: - name: kube-apiserver-ca vault: # Все переменные global.Vault.* могут быть переопределены тут в блоке vault - intermediate: # Альтернатива блоку certificates.intermediate_ca - path: "clusters/cluster-1/pki/kube-apiserver" # альтернатива блоку csr[*].cert_path - rootPath: "clusters/cluster-1/pki/root" - exportedKey: false - generate: false + role: + name: "kube-apiserver-ca" # альтернатива блоку csr[*].role + path: "clusters/cluster-1/pki/kube-apiserver" # альтернатива блоку csr[*].cert_path + intermediate: # Альтернатива блоку certificates.intermediate_ca + rootPath: "clusters/cluster-1/pki/root" + exportedKey: false + generate: false certificates: - name: kube-apiserver-server From efed6388892054877d2713f1a3e54edf00b23d9a Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Sat, 20 Aug 2022 18:39:25 +0300 Subject: [PATCH 091/220] =?UTF-8?q?=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test.example.yaml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/test.example.yaml b/test.example.yaml index 2e2957c..3a584fb 100644 --- a/test.example.yaml +++ b/test.example.yaml @@ -37,10 +37,22 @@ issuers: role: name: "kube-apiserver-ca" # альтернатива блоку csr[*].role path: "clusters/cluster-1/pki/kube-apiserver" # альтернатива блоку csr[*].cert_path + # Если в сертификате указан isCA=true то смотреть в блок intermediate за до параметрами, во всех других игнорировать. intermediate: # Альтернатива блоку certificates.intermediate_ca rootPath: "clusters/cluster-1/pki/root" exportedKey: false generate: false + # при указании generate: false в сертификате игнорируются поля ниже т.к ЦА уже создан и нам нужен публичный ключ. + # subject: # https://www.vaultproject.io/api-docs/secret/pki + # # vault write pki/issue/example_role organization="example.inc" ou="development team" country="EX" + # organizations: [] + # ous: [] + # countrys: [] + # commonName: kube-apiserver-ca + # privateKey: + # algorithm: RSA + # encoding: PKCS1 + # size: 2048 certificates: - name: kube-apiserver-server @@ -72,7 +84,7 @@ certificates: hostPathCert: "/etc/kubernetes/pki/certs/kube-apiserver/cert" trigger: - systemctl stop kube-apiserver.service - httpCheck: 127.0.0.1:6443 + httpsCheck: 127.0.0.1:6443 - name: kube-apiserver-ca spec: @@ -95,7 +107,7 @@ certificates: hostPathCert: "/etc/kubernetes/pki/ca" trigger: - systemctl stop kube-apiserver.service - httpCheck: 127.0.0.1:6443 + httpsCheck: 127.0.0.1:6443 keys: - name: system:kube-apiserver-sa From 88c7b4c6119d5ffec6401275e4d5b5a06e861f2b Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Sat, 20 Aug 2022 19:22:30 +0300 Subject: [PATCH 092/220] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=B8=D1=82=D0=BE=D0=B3=D0=BE=D0=B2=D1=8B=D0=B9?= =?UTF-8?q?=20=D0=BF=D1=80=D0=B8=D0=BC=D0=B5=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example.yaml | 420 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 420 insertions(+) create mode 100644 example.yaml diff --git a/example.yaml b/example.yaml new file mode 100644 index 0000000..2a93a9b --- /dev/null +++ b/example.yaml @@ -0,0 +1,420 @@ +--- +global: + vault: + serever: "http://51.250.67.8:9200" + caBundle: "" + tlsInsecure: true + auth: + bootstrap: + tokenPath: "$TOKEN" + appRole: + name: test-role + path: clusters/cluster-1/approle + roleIdPath: "$PATH" + secretIdPath: "$PATH" + kv: "clusters/cluster-1/kv" + +issuers: + - name: front-proxy-client + vault: + role: + name: "front-proxy-client" + path: "clusters/${cluster_name}/pki/front-proxy" + + - name: kube-apiserver + vault: + role: + name: "kube-apiserver" + path: "clusters/${cluster_name}/pki/kubernetes" + + - name: kube-apiserver-kubelet-client + vault: + role: + name: "kube-apiserver-kubelet-client" + path: "clusters/${cluster_name}/pki/kubernetes" + + - name: kube-controller-manager-client + vault: + role: + name: "kube-controller-manager-client" + path: "clusters/${cluster_name}/pki/kubernetes" + + - name: kube-controller-manager-server + vault: + role: + name: "kube-controller-manager-server" + path: "clusters/${cluster_name}/pki/kubernetes" + + - name: kube-scheduler-client + vault: + role: + name: "kube-scheduler-client" + path: "clusters/${cluster_name}/pki/kubernetes" + + - name: kubelet-client + vault: + role: + name: "kubelet-client" + path: "clusters/${cluster_name}/pki/kubernetes" + + - name: etcd-client + vault: + role: + name: "kubelet-client" + path: "clusters/${cluster_name}/pki/etcd" + + - name: etcd-peer + vault: + role: + name: "etcd-peer" + path: "clusters/${cluster_name}/pki/etcd" + + - name: etcd-server + vault: + role: + name: "etcd-server" + path: "clusters/${cluster_name}/pki/etcd" + + - name: root-ca + vault: + role: + name: "root" + path: "clusters/cluster-1/pki/kubernetes" + intermediate: + rootPath: "clusters/cluster-1/pki/root" + exportedKey: false + generate: false + + - name: root-ca + vault: + role: + name: "root" + path: "clusters/${cluster_name}/pki/etcd" + intermediate: + rootPath: "clusters/cluster-1/pki/root" + exportedKey: false + generate: false + + - name: root-ca + vault: + role: + name: "root" + path: "clusters/${cluster_name}/pki/front-proxy" + intermediate: + rootPath: "clusters/cluster-1/pki/root" + exportedKey: false + generate: false + +certificates: + - name: root-ca + spec: + isCa: true + issuerRef: + name: root-ca + hostPathCert: "/etc/kubernetes/pki/ca" + + - name: etcd-ca + spec: + isCa: true + issuerRef: + name: etcd-ca + hostPathCert: "/etc/kubernetes/pki/ca" + + - name: front-proxy-ca + spec: + isCa: true + issuerRef: + name: front-proxy-ca + hostPathCert: "/etc/kubernetes/pki/ca" + + - name: system:kube-apiserver-front-proxy-client + spec: + duration: 2160h + renewBefore: 360h + subject: + organizations: + - system:masters + commonName: system:kube-apiserver-front-proxy-client + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 2048 + usages: + - client auth + issuerRef: + name: front-proxy-client + hostPathCert: "/etc/kubernetes/pki/certs/kube-apiserver/certs" + + - name: system:kube-apiserver-etcd-client + spec: + duration: 2160h + renewBefore: 360h + subject: + organizations: + - system:masters + commonName: system:kube-apiserver-etcd-client + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 2048 + usages: + - client auth + issuerRef: + name: etcd-client + hostPathCert: "/etc/kubernetes/pki/certs/kube-apiserver/certs" + + - name: system:kube-apiserver-server + spec: + duration: 2160h + renewBefore: 360h + commonName: system:kube-apiserver-server + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 2048 + usages: + - server auth + dnsNames: + - system:kube-apiserver-server + - "localhost" + - "kubernetes" + - "kubernetes.default" + - "kubernetes.default.svc" + - "kubernetes.default.svc.cluster" + - "kubernetes.default.svc.cluster.local" + - "api.cluster-1.example.com" + ipAddresses: + - "127.0.0.1" + - "127.0.1.1" + - "127.0.1.6" + - "29.64.0.1" + issuerRef: + name: kube-apiserver + hostPathCert: "/etc/kubernetes/pki/certs/kube-apiserver/certs" + trigger: + - systemctl stop kube-apiserver.service + httpsCheck: 127.0.0.1:6443 + + - name: system:kube-apiserver-kubelet-client + spec: + duration: 2160h + renewBefore: 360h + subject: + organizations: + - system:masters + commonName: system:kube-apiserver-kubelet-client + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 2048 + usages: + - client auth + issuerRef: + name: kube-apiserver-kubelet-client + hostPathCert: "/etc/kubernetes/pki/certs/kube-apiserver/certs" + + - name: system:kube-controller-manager-client + spec: + duration: 2160h + renewBefore: 360h + subject: + organizations: + - system:masters + commonName: system:kube-controller-manager + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 2048 + usages: + - client auth + issuerRef: + name: kube-controller-manager-client + hostPathCert: "/etc/kubernetes/pki/certs/kube-controller-manager/certs" + + - name: system:kube-controller-manager-server + spec: + duration: 2160h + renewBefore: 360h + commonName: system:kube-controller-manager-server + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 2048 + usages: + - server auth + dnsNames: + - "localhost" + - "kube-controller-manager.default" + - "kube-controller-manager.default.svc" + - "kube-controller-manager.default.svc.cluster" + - "kube-controller-manager.default.svc.cluster.local" + ipAddresses: + - "127.0.0.1" + - "127.0.1.1" + - "127.0.1.6" + issuerRef: + name: kube-controller-manager-server + hostPathCert: "/etc/kubernetes/pki/certs/kube-controller-manager/certs" + trigger: + - systemctl stop kube-controller-manager.service + httpsCheck: 127.0.0.1:6443 + + - name: system:kube-scheduler-client + spec: + duration: 2160h + renewBefore: 360h + subject: + organizations: + - system:masters + commonName: system:kube-scheduler + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 2048 + usages: + - client auth + issuerRef: + name: kube-scheduler-client + hostPathCert: "/etc/kubernetes/pki/certs/kube-scheduler/certs" + + - name: system:kube-scheduler-server + spec: + duration: 2160h + renewBefore: 360h + commonName: system:kube-scheduler-server + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 2048 + usages: + - server auth + dnsNames: + - "localhost" + - "kube-scheduler.default" + - "kube-scheduler.default.svc" + - "kube-scheduler.default.svc.cluster" + - "kube-scheduler.default.svc.cluster.local" + ipAddresses: + - "127.0.0.1" + - "127.0.1.1" + - "127.0.1.6" + issuerRef: + name: kube-scheduler-server + hostPathCert: "/etc/kubernetes/pki/certs/kube-scheduler/certs" + trigger: + - systemctl stop kube-scheduler.service + httpsCheck: 127.0.0.1:6443 + + - name: system:kube-scheduler-client + spec: + duration: 2160h + renewBefore: 360h + subject: + organizations: + - system:masters + commonName: system:kube-scheduler + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 2048 + usages: + - client auth + issuerRef: + name: kube-scheduler-client + hostPathCert: "/etc/kubernetes/pki/certs/kube-scheduler/certs" + + - name: system:node:${ instance_name }.${ base_domain } + spec: + duration: 2160h + renewBefore: 360h + subject: + organizations: + - system:masters + commonName: system:node:${ instance_name }.${ base_domain } + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 2048 + usages: + - client auth + issuerRef: + name: kubelet-client + hostPathCert: "/etc/kubernetes/pki/certs/kubelet/certs" + + - name: system:etcd-healthcheck-client + spec: + duration: 2160h + renewBefore: 360h + commonName: system:etcd-healthcheck-client + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 2048 + usages: + - client auth + issuerRef: + name: etcd-client + hostPathCert: "/etc/kubernetes/pki/certs/kubelet/etcd" + + - name: system:etcd-peer + spec: + duration: 2160h + renewBefore: 360h + commonName: system:etcd-peer + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 2048 + usages: + - server auth + - client auth + dnsNames: + - "localhost" + - "${ instance_name }.${base_domain}" + ipAddresses: + - "127.0.0.1" + - "127.0.1.1" + - "127.0.1.6" + issuerRef: + name: etcd-peer + hostPathCert: "/etc/kubernetes/pki/certs/etcd/certs" + trigger: + - systemctl stop etcd.service + httpsCheck: 127.0.0.1:2379 + + - name: system:etcd-server + spec: + duration: 2160h + renewBefore: 360h + commonName: system:etcd-server + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 2048 + usages: + - server auth + - client auth + dnsNames: + - "localhost" + - "${ instance_name }.${base_domain}" + ipAddresses: + - "127.0.0.1" + - "127.0.1.1" + - "127.0.1.6" + issuerRef: + name: etcd-server + hostPathCert: "/etc/kubernetes/pki/certs/etcd/certs" + trigger: + - systemctl stop etcd.service + httpsCheck: 127.0.0.1:2380 + +keys: + - name: system:kube-apiserver-sa + host_path: /etc/kubernetes/pki/certs/kube-apiserver/ + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 2048 + public: true + vault: + kv: "clusters/${cluster_name}/kv" From c20768b85156ee34b060bcea466ac773e8909132 Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Sat, 20 Aug 2022 19:24:20 +0300 Subject: [PATCH 093/220] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example.yaml b/example.yaml index 2a93a9b..e8750c5 100644 --- a/example.yaml +++ b/example.yaml @@ -85,7 +85,7 @@ issuers: exportedKey: false generate: false - - name: root-ca + - name: etcd-ca vault: role: name: "root" @@ -95,7 +95,7 @@ issuers: exportedKey: false generate: false - - name: root-ca + - name: front-proxy vault: role: name: "root" From e52de397a34882a241a86c3154ed142b2c1ea5ef Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Sat, 20 Aug 2022 19:28:55 +0300 Subject: [PATCH 094/220] =?UTF-8?q?=D0=A4=D0=B8=D0=BA=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example.yaml | 43 ++++++++++++++----------------------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/example.yaml b/example.yaml index e8750c5..36249a9 100644 --- a/example.yaml +++ b/example.yaml @@ -19,61 +19,61 @@ issuers: vault: role: name: "front-proxy-client" - path: "clusters/${cluster_name}/pki/front-proxy" + path: "clusters/cluster-1/pki/front-proxy" - name: kube-apiserver vault: role: name: "kube-apiserver" - path: "clusters/${cluster_name}/pki/kubernetes" + path: "clusters/cluster-1/pki/kubernetes" - name: kube-apiserver-kubelet-client vault: role: name: "kube-apiserver-kubelet-client" - path: "clusters/${cluster_name}/pki/kubernetes" + path: "clusters/cluster-1/pki/kubernetes" - name: kube-controller-manager-client vault: role: name: "kube-controller-manager-client" - path: "clusters/${cluster_name}/pki/kubernetes" + path: "clusters/cluster-1/pki/kubernetes" - name: kube-controller-manager-server vault: role: name: "kube-controller-manager-server" - path: "clusters/${cluster_name}/pki/kubernetes" + path: "clusters/cluster-1/pki/kubernetes" - name: kube-scheduler-client vault: role: name: "kube-scheduler-client" - path: "clusters/${cluster_name}/pki/kubernetes" + path: "clusters/cluster-1/pki/kubernetes" - name: kubelet-client vault: role: name: "kubelet-client" - path: "clusters/${cluster_name}/pki/kubernetes" + path: "clusters/cluster-1/pki/kubernetes" - name: etcd-client vault: role: name: "kubelet-client" - path: "clusters/${cluster_name}/pki/etcd" + path: "clusters/cluster-1/pki/etcd" - name: etcd-peer vault: role: name: "etcd-peer" - path: "clusters/${cluster_name}/pki/etcd" + path: "clusters/cluster-1/pki/etcd" - name: etcd-server vault: role: name: "etcd-server" - path: "clusters/${cluster_name}/pki/etcd" + path: "clusters/cluster-1/pki/etcd" - name: root-ca vault: @@ -89,7 +89,7 @@ issuers: vault: role: name: "root" - path: "clusters/${cluster_name}/pki/etcd" + path: "clusters/cluster-1/pki/etcd" intermediate: rootPath: "clusters/cluster-1/pki/root" exportedKey: false @@ -99,7 +99,7 @@ issuers: vault: role: name: "root" - path: "clusters/${cluster_name}/pki/front-proxy" + path: "clusters/cluster-1/pki/front-proxy" intermediate: rootPath: "clusters/cluster-1/pki/root" exportedKey: false @@ -131,9 +131,6 @@ certificates: spec: duration: 2160h renewBefore: 360h - subject: - organizations: - - system:masters commonName: system:kube-apiserver-front-proxy-client privateKey: algorithm: RSA @@ -149,9 +146,6 @@ certificates: spec: duration: 2160h renewBefore: 360h - subject: - organizations: - - system:masters commonName: system:kube-apiserver-etcd-client privateKey: algorithm: RSA @@ -217,9 +211,6 @@ certificates: spec: duration: 2160h renewBefore: 360h - subject: - organizations: - - system:masters commonName: system:kube-controller-manager privateKey: algorithm: RSA @@ -263,9 +254,6 @@ certificates: spec: duration: 2160h renewBefore: 360h - subject: - organizations: - - system:masters commonName: system:kube-scheduler privateKey: algorithm: RSA @@ -309,9 +297,6 @@ certificates: spec: duration: 2160h renewBefore: 360h - subject: - organizations: - - system:masters commonName: system:kube-scheduler privateKey: algorithm: RSA @@ -329,7 +314,7 @@ certificates: renewBefore: 360h subject: organizations: - - system:masters + - system:nodes commonName: system:node:${ instance_name }.${ base_domain } privateKey: algorithm: RSA @@ -417,4 +402,4 @@ keys: size: 2048 public: true vault: - kv: "clusters/${cluster_name}/kv" + kv: "clusters/cluster-1/kv" From 26cfcc1efdc21f7a98cc29227afe83b82a4c49dd Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Sat, 20 Aug 2022 22:03:15 +0300 Subject: [PATCH 095/220] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example.yaml | 3 ++- test.example.yaml | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/example.yaml b/example.yaml index 36249a9..78fa571 100644 --- a/example.yaml +++ b/example.yaml @@ -12,7 +12,8 @@ global: path: clusters/cluster-1/approle roleIdPath: "$PATH" secretIdPath: "$PATH" - kv: "clusters/cluster-1/kv" + kv: + path: "clusters/cluster-1/kv" issuers: - name: front-proxy-client diff --git a/test.example.yaml b/test.example.yaml index 3a584fb..ac4b507 100644 --- a/test.example.yaml +++ b/test.example.yaml @@ -12,7 +12,8 @@ global: path: clusters/cluster-1/approle # rename $approle_path roleIdPath: "$PATH" # rename $local_path_to_role_id secretIdPath: "$PATH" # rename $local_path_to_secret_id - kv: "clusters/${cluster_name}/kv" + kv: + path: "clusters/${cluster_name}/kv" issuers: - name: kube-apiserver-server @@ -118,4 +119,5 @@ keys: size: 2048 public: true # если false генерил локально, true генерил локально и пушил в vault vault: - kv: "clusters/${cluster_name}/kv" + kv: + path: "clusters/${cluster_name}/kv" From 117e044e692edc8fa516674024c6d83f234ed177 Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Sat, 20 Aug 2022 23:11:25 +0300 Subject: [PATCH 096/220] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example.yaml | 126 +++++++++++++++++++++++---------------------------- 1 file changed, 56 insertions(+), 70 deletions(-) diff --git a/example.yaml b/example.yaml index 78fa571..5f08156 100644 --- a/example.yaml +++ b/example.yaml @@ -16,12 +16,32 @@ global: path: "clusters/cluster-1/kv" issuers: + - name: front-proxy-ca + vault: + role: + name: "root" + path: "clusters/cluster-1/pki/front-proxy" + intermediate: + rootPath: "clusters/cluster-1/pki/root" + exportedKey: false + generate: false + - name: front-proxy-client vault: role: name: "front-proxy-client" path: "clusters/cluster-1/pki/front-proxy" + - name: kube-ca + vault: + role: + name: "root" + path: "clusters/cluster-1/pki/kubernetes" + intermediate: + rootPath: "clusters/cluster-1/pki/root" + exportedKey: false + generate: false + - name: kube-apiserver vault: role: @@ -58,6 +78,16 @@ issuers: name: "kubelet-client" path: "clusters/cluster-1/pki/kubernetes" + - name: etcd-ca + vault: + role: + name: "root" + path: "clusters/cluster-1/pki/etcd" + intermediate: + rootPath: "clusters/cluster-1/pki/root" + exportedKey: false + generate: false + - name: etcd-client vault: role: @@ -76,50 +106,7 @@ issuers: name: "etcd-server" path: "clusters/cluster-1/pki/etcd" - - name: root-ca - vault: - role: - name: "root" - path: "clusters/cluster-1/pki/kubernetes" - intermediate: - rootPath: "clusters/cluster-1/pki/root" - exportedKey: false - generate: false - - - name: etcd-ca - vault: - role: - name: "root" - path: "clusters/cluster-1/pki/etcd" - intermediate: - rootPath: "clusters/cluster-1/pki/root" - exportedKey: false - generate: false - - - name: front-proxy - vault: - role: - name: "root" - path: "clusters/cluster-1/pki/front-proxy" - intermediate: - rootPath: "clusters/cluster-1/pki/root" - exportedKey: false - generate: false - certificates: - - name: root-ca - spec: - isCa: true - issuerRef: - name: root-ca - hostPathCert: "/etc/kubernetes/pki/ca" - - - name: etcd-ca - spec: - isCa: true - issuerRef: - name: etcd-ca - hostPathCert: "/etc/kubernetes/pki/ca" - name: front-proxy-ca spec: @@ -143,20 +130,12 @@ certificates: name: front-proxy-client hostPathCert: "/etc/kubernetes/pki/certs/kube-apiserver/certs" - - name: system:kube-apiserver-etcd-client + - name: kube-ca spec: - duration: 2160h - renewBefore: 360h - commonName: system:kube-apiserver-etcd-client - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 2048 - usages: - - client auth + isCa: true issuerRef: - name: etcd-client - hostPathCert: "/etc/kubernetes/pki/certs/kube-apiserver/certs" + name: root-ca + hostPathCert: "/etc/kubernetes/pki/ca" - name: system:kube-apiserver-server spec: @@ -251,21 +230,6 @@ certificates: - systemctl stop kube-controller-manager.service httpsCheck: 127.0.0.1:6443 - - name: system:kube-scheduler-client - spec: - duration: 2160h - renewBefore: 360h - commonName: system:kube-scheduler - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 2048 - usages: - - client auth - issuerRef: - name: kube-scheduler-client - hostPathCert: "/etc/kubernetes/pki/certs/kube-scheduler/certs" - - name: system:kube-scheduler-server spec: duration: 2160h @@ -327,6 +291,13 @@ certificates: name: kubelet-client hostPathCert: "/etc/kubernetes/pki/certs/kubelet/certs" + - name: etcd-ca + spec: + isCa: true + issuerRef: + name: etcd-ca + hostPathCert: "/etc/kubernetes/pki/ca" + - name: system:etcd-healthcheck-client spec: duration: 2160h @@ -394,6 +365,21 @@ certificates: - systemctl stop etcd.service httpsCheck: 127.0.0.1:2380 + - name: system:kube-apiserver-etcd-client + spec: + duration: 2160h + renewBefore: 360h + commonName: system:kube-apiserver-etcd-client + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 2048 + usages: + - client auth + issuerRef: + name: etcd-client + hostPathCert: "/etc/kubernetes/pki/certs/kube-apiserver/certs" + keys: - name: system:kube-apiserver-sa host_path: /etc/kubernetes/pki/certs/kube-apiserver/ From 3d702370aa93d81c9d20048839f0b855f904eae7 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 23 Aug 2022 17:22:11 +0300 Subject: [PATCH 097/220] update --- cmd/key-keeper/main.go | 15 ++++-- example.yaml | 31 ++++++------ internal/controller/config.go | 17 ------- internal/controller/config2.go | 66 ++++++++++++++++++++++++++ internal/vault/vault.go | 22 ++++----- test.example.yaml | 87 ++++++++++++++++------------------ 6 files changed, 146 insertions(+), 92 deletions(-) create mode 100644 internal/controller/config2.go diff --git a/cmd/key-keeper/main.go b/cmd/key-keeper/main.go index 74f1c78..5affb2d 100644 --- a/cmd/key-keeper/main.go +++ b/cmd/key-keeper/main.go @@ -27,13 +27,22 @@ func main() { } zap.ReplaceGlobals(logger) - var configDir, configNameLayout string + var globalConfig, configDir, configNameLayout string + flag.StringVar(&globalConfig, "config-global", "", "path to global config") flag.StringVar(&configDir, "config-dir", "", "path to dir with configs") - flag.StringVar(&configDir, "config-regexp", "", "regexp for config names") + flag.StringVar(&configNameLayout, "config-regexp", "", "regexp for config files names") flag.Parse() + if globalConfig == "" { + zap.L().Fatal("not found global config param") + } + if configDir == "" { - zap.L().Fatal("not found config param") + zap.L().Fatal("not found config path param") + } + + if configNameLayout == "" { + zap.L().Fatal("not found regexp for config file's name") } cfg, err := config.New(configDir, configNameLayout) diff --git a/example.yaml b/example.yaml index 5f08156..de05703 100644 --- a/example.yaml +++ b/example.yaml @@ -12,13 +12,13 @@ global: path: clusters/cluster-1/approle roleIdPath: "$PATH" secretIdPath: "$PATH" - kv: + kv: path: "clusters/cluster-1/kv" issuers: - name: front-proxy-ca vault: - role: + role: name: "root" path: "clusters/cluster-1/pki/front-proxy" intermediate: @@ -28,13 +28,13 @@ issuers: - name: front-proxy-client vault: - role: + role: name: "front-proxy-client" path: "clusters/cluster-1/pki/front-proxy" - name: kube-ca vault: - role: + role: name: "root" path: "clusters/cluster-1/pki/kubernetes" intermediate: @@ -44,43 +44,43 @@ issuers: - name: kube-apiserver vault: - role: + role: name: "kube-apiserver" path: "clusters/cluster-1/pki/kubernetes" - name: kube-apiserver-kubelet-client vault: - role: + role: name: "kube-apiserver-kubelet-client" path: "clusters/cluster-1/pki/kubernetes" - name: kube-controller-manager-client vault: - role: + role: name: "kube-controller-manager-client" path: "clusters/cluster-1/pki/kubernetes" - name: kube-controller-manager-server vault: - role: + role: name: "kube-controller-manager-server" path: "clusters/cluster-1/pki/kubernetes" - name: kube-scheduler-client vault: - role: + role: name: "kube-scheduler-client" path: "clusters/cluster-1/pki/kubernetes" - name: kubelet-client vault: - role: + role: name: "kubelet-client" path: "clusters/cluster-1/pki/kubernetes" - name: etcd-ca vault: - role: + role: name: "root" path: "clusters/cluster-1/pki/etcd" intermediate: @@ -90,31 +90,30 @@ issuers: - name: etcd-client vault: - role: + role: name: "kubelet-client" path: "clusters/cluster-1/pki/etcd" - name: etcd-peer vault: - role: + role: name: "etcd-peer" path: "clusters/cluster-1/pki/etcd" - name: etcd-server vault: - role: + role: name: "etcd-server" path: "clusters/cluster-1/pki/etcd" certificates: - - name: front-proxy-ca spec: isCa: true issuerRef: name: front-proxy-ca hostPathCert: "/etc/kubernetes/pki/ca" - + - name: system:kube-apiserver-front-proxy-client spec: duration: 2160h diff --git a/internal/controller/config.go b/internal/controller/config.go index 08a73cb..0effa7c 100644 --- a/internal/controller/config.go +++ b/internal/controller/config.go @@ -9,23 +9,6 @@ type Config struct { Recource RecourceConfig `yaml:",inline"` } -// VaultConfig for work with vault -type VaultConfig struct { - Address string `yaml:"address"` - BootsrapToken string `yaml:"bootstrap_token"` - AppRolePath string `yaml:"approle_path"` - AppRoleName string `yaml:"approle_name"` - LocalPathToRoleID string `yaml:"local_path_to_role_id"` - LocalPathToSecretID string `yaml:"local_path_to_secret_id"` - RequestTimeout time.Duration `yaml:"request_timeout"` -} - -// RecourceConfig for work controller. -type RecourceConfig struct { - Certificates Certificates `json:"certificates"` - Keys Keys `json:"keys"` -} - type Certificates struct { VaultKV string `yaml:"vault_kv"` ReissueInterval time.Duration `yaml:"reissue_interval"` diff --git a/internal/controller/config2.go b/internal/controller/config2.go new file mode 100644 index 0000000..287bc5f --- /dev/null +++ b/internal/controller/config2.go @@ -0,0 +1,66 @@ +package controller + +import "time" + +type GlobalConfig struct{} + +type IssuerConfig struct { + Issuers []issuer `yaml:",inline"` +} + +type RecourceConfig struct { + Certificates []Certificate `json:"certificates"` + Keys Keys `json:"keys"` +} + +type issuer struct { + Name string `yaml:"name"` + Vault VaultConfig `yaml:""` +} + +// VaultConfig for work with vault +type VaultConfig struct { + Server string `yaml:"address"` + CABundle string `yaml:"caBundle"` + Auth struct { + Bootstrap struct { + Token string `yaml:"token"` + } `yaml:"bootstrap"` + AppRole struct { + Name string `yaml:"name"` + Path string `yaml:"path"` + RoleIDLocalPath string `yaml:"roleIDLocalPath"` + SecretIDLocalPath string `yaml:"secretIDLocalPath"` + } + } `yaml:"auth"` + RequestTimeout time.Duration `yaml:"request_timeout"` +} + +type Certificate struct { + Name string `yaml:"name"` + Spec certificateSpec `yaml:"spec"` + HostPath string `yaml:"hostPath"` + Trigger []string `yaml:"trigger"` +} + +type certificateSpec struct { + CommonName string `yaml:"commonName"` + Subject struct { + Organizations []string `yaml:"organizations"` + Ous []string `yaml:"ous"` + Countries []string `yaml:"countries"` + } `yaml:"subject"` + PrivateKey struct { + Algorithm string `yaml:"algorithm"` + Encoding string `yaml:"encoding"` + Size int `yaml:"size"` + } `yaml:"privateKey"` + Usages []string `yaml:"usages"` + DNSNames []string `yaml:"dnsNames"` + IPAddresses []string `yaml:"ipAddresses"` + IssuerRef struct { + Name string `yaml:"name"` + } `yaml:"issuerRef"` + Lifespan string `yaml:"lifespan"` + RenewBefore time.Duration `yaml:"renewBefore"` +} diff --git a/internal/vault/vault.go b/internal/vault/vault.go index 72a8759..bef7978 100644 --- a/internal/vault/vault.go +++ b/internal/vault/vault.go @@ -19,7 +19,7 @@ type vault struct { func Connect(cfg controller.VaultConfig) (controller.Vault, error) { client, err := api.NewClient( &api.Config{ - Address: cfg.Address, + Address: cfg.Server, HttpClient: &http.Client{ Timeout: cfg.RequestTimeout, }, @@ -28,7 +28,7 @@ func Connect(cfg controller.VaultConfig) (controller.Vault, error) { if err != nil { return nil, fmt.Errorf("new vault client: %w", err) } - client.SetToken(cfg.BootsrapToken) + client.SetToken(cfg.Auth.Bootstrap.Token) s := &vault{ cli: client, @@ -48,7 +48,7 @@ func Connect(cfg controller.VaultConfig) (controller.Vault, error) { &auth.SecretID{ FromString: secretID, }, - auth.WithMountPath(cfg.AppRolePath), + auth.WithMountPath(cfg.Auth.AppRole.Path), ) if err != nil { return nil, err @@ -65,10 +65,10 @@ func Connect(cfg controller.VaultConfig) (controller.Vault, error) { } func (s *vault) roleID(cfg controller.VaultConfig) (string, error) { - path := path.Join("auth", cfg.AppRolePath, "role", cfg.AppRoleName, "role-id") + path := path.Join("auth", cfg.Auth.AppRole.Path, "role", cfg.Auth.AppRole.Name, "role-id") approle, err := s.Read(path) if err != nil { - if roleID, rErr := readFromFile(cfg.LocalPathToRoleID); rErr == nil { + if roleID, rErr := readFromFile(cfg.Auth.AppRole.RoleIDLocalPath); rErr == nil { return string(roleID), nil } return "", fmt.Errorf("read role_id for path: %s : %w", path, err) @@ -81,17 +81,17 @@ func (s *vault) roleID(cfg controller.VaultConfig) (string, error) { if !ok { return "", fmt.Errorf("not found role_id") } - if err = writeToFile(cfg.LocalPathToRoleID, roleID.(string)); err != nil { - return "", fmt.Errorf("save role id path: %s id: %w", cfg.LocalPathToRoleID, err) + if err = writeToFile(cfg.Auth.AppRole.RoleIDLocalPath, roleID.(string)); err != nil { + return "", fmt.Errorf("save role id path: %s id: %w", cfg.Auth.AppRole.RoleIDLocalPath, err) } return roleID.(string), err } func (s *vault) secretID(cfg controller.VaultConfig) (string, error) { - path := path.Join("auth", cfg.AppRolePath, "role", cfg.AppRoleName, "secret-id") + path := path.Join("auth", cfg.Auth.AppRole.Path, "role", cfg.Auth.AppRole.Name, "secret-id") approle, err := s.Write(path, nil) if err != nil { - if secretID, rErr := readFromFile(cfg.LocalPathToSecretID); rErr == nil { + if secretID, rErr := readFromFile(cfg.Auth.AppRole.SecretIDLocalPath); rErr == nil { return string(secretID), nil } return "", fmt.Errorf("read secrete_id for path: %s : %w", path, err) @@ -105,8 +105,8 @@ func (s *vault) secretID(cfg controller.VaultConfig) (string, error) { return "", fmt.Errorf("not found secrete_id") } - if err = writeToFile(cfg.LocalPathToSecretID, secretID.(string)); err != nil { - return "", fmt.Errorf("save secret id path: %s id: %w", cfg.LocalPathToSecretID, err) + if err = writeToFile(cfg.Auth.AppRole.SecretIDLocalPath, secretID.(string)); err != nil { + return "", fmt.Errorf("save secret id path: %s id: %w", cfg.Auth.AppRole.SecretIDLocalPath, err) } return secretID.(string), err } diff --git a/test.example.yaml b/test.example.yaml index ac4b507..60db0fa 100644 --- a/test.example.yaml +++ b/test.example.yaml @@ -1,54 +1,55 @@ --- global: vault: - serever: "http://${VAULT_IP}" # rename $address - caBundle: "" # new (сертификат для подключения к волту - при http не должен фигурировать) - tlsInsecure: true # new при указании тру скипать ssl верификацию + serever: "http://${VAULT_IP}" # rename $address + caBundle: "" # new (сертификат для подключения к волту - при http не должен фигурировать) + tlsInsecure: true # new при указании тру скипать ssl верификацию auth: bootstrap: - tokenPath: "" # rename $bootstrap_token + token: "" # rename $bootstrap_token appRole: - name: test-role # rename $approle_name - path: clusters/cluster-1/approle # rename $approle_path - roleIdPath: "$PATH" # rename $local_path_to_role_id - secretIdPath: "$PATH" # rename $local_path_to_secret_id - kv: + name: test-role # rename $approle_name + path: clusters/cluster-1/approle # rename $approle_path + roleIDLocalPath: "$PATH" # rename $local_path_to_role_id + SecretIDLocalPath: "$PATH" # rename $local_path_to_secret_id + kv: path: "clusters/${cluster_name}/kv" issuers: - name: kube-apiserver-server - vault: # Все переменные global.Vault.* могут быть переопределены тут в блоке vault - role: - name: "system_masters_client" # альтернатива блоку csr[*].role + vault: # Все переменные global.Vault.* могут быть переопределены тут в блоке vault + role: + name: "system_masters_client" # альтернатива блоку csr[*].role path: "clusters/cluster-1/pki/kube-apiserver" # альтернатива блоку csr[*].cert_path - serever: "http://${VAULT_IP}" # rename $address - caBundle: "" # new (сертификат для подключения к волту - при http не должен фигурировать) - tlsInsecure: true # new при указании тру скипать ssl верификацию + serever: "http://${VAULT_IP}" # rename $address + caBundle: "" # new (сертификат для подключения к волту - при http не должен фигурировать) + tlsInsecure: true # new при указании тру скипать ssl верификацию auth: bootstrap: - tokenPath: "" # rename $bootstrap_token + token: "" # rename $bootstrap_token appRole: - name: test-role # rename $approle_name - path: clusters/cluster-1/approle # rename $approle_path - roleIdPath: "$PATH" # rename $local_path_to_role_id - secretIdPath: "$PATH" # rename $local_path_to_secret_id + name: test-role # rename $approle_name + path: clusters/cluster-1/approle # rename $approle_path + roleIdPath: "$PATH" # rename $local_path_to_role_id + secretIdPath: "$PATH" # rename $local_path_to_secret_id - name: kube-apiserver-ca - vault: # Все переменные global.Vault.* могут быть переопределены тут в блоке vault - role: - name: "kube-apiserver-ca" # альтернатива блоку csr[*].role - path: "clusters/cluster-1/pki/kube-apiserver" # альтернатива блоку csr[*].cert_path + vault: # Все переменные global.Vault.* могут быть переопределены тут в блоке vault + role: + name: "kube-apiserver-ca" # альтернатива блоку csr[*].role + path: "clusters/cluster-1/pki/kube-apiserver" # альтернатива блоку csr[*].cert_path # Если в сертификате указан isCA=true то смотреть в блок intermediate за до параметрами, во всех других игнорировать. - intermediate: # Альтернатива блоку certificates.intermediate_ca + intermediate: # Альтернатива блоку certificates.intermediate_ca rootPath: "clusters/cluster-1/pki/root" exportedKey: false - generate: false + generate: + false # при указании generate: false в сертификате игнорируются поля ниже т.к ЦА уже создан и нам нужен публичный ключ. - # subject: # https://www.vaultproject.io/api-docs/secret/pki + # subject: # https://www.vaultproject.io/api-docs/secret/pki # # vault write pki/issue/example_role organization="example.inc" ou="development team" country="EX" # organizations: [] # ous: [] - # countrys: [] + # countries: [] # commonName: kube-apiserver-ca # privateKey: # algorithm: RSA @@ -58,14 +59,14 @@ issuers: certificates: - name: kube-apiserver-server spec: - duration: 2160h # на какой промежуток времени заказывается сертификат - renewBefore: 360h # за сколько до истечения надо перевыпустить - subject: # https://www.vaultproject.io/api-docs/secret/pki + lifespan: 2160h # на какой промежуток времени заказывается сертификат + renewBefore: 360h # за сколько до истечения надо перевыпустить + subject: # https://www.vaultproject.io/api-docs/secret/pki # vault write pki/issue/example_role organization="example.inc" ou="development team" country="EX" organizations: - system:masters ous: [] - countrys: [] + countries: [] commonName: kube-apiserver-server privateKey: algorithm: RSA @@ -81,21 +82,19 @@ certificates: - 127.0.0.1 issuerRef: name: kube-apiserver-server - - hostPathCert: "/etc/kubernetes/pki/certs/kube-apiserver/cert" + hostPath: "/etc/kubernetes/pki/certs/kube-apiserver/cert" trigger: - systemctl stop kube-apiserver.service - httpsCheck: 127.0.0.1:6443 - name: kube-apiserver-ca spec: - duration: 2160h # на какой промежуток времени заказывается сертификат - renewBefore: 360h # за сколько до истечения надо перевыпустить - subject: # https://www.vaultproject.io/api-docs/secret/pki + lifespan: 2160h # на какой промежуток времени заказывается сертификат + renewBefore: 360h # за сколько до истечения надо перевыпустить + subject: # https://www.vaultproject.io/api-docs/secret/pki # vault write pki/issue/example_role organization="example.inc" ou="development team" country="EX" organizations: [] ous: [] - countrys: [] + countries: [] commonName: kube-apiserver-ca privateKey: algorithm: RSA @@ -104,20 +103,18 @@ certificates: isCa: true issuerRef: name: kube-apiserver-ca - - hostPathCert: "/etc/kubernetes/pki/ca" + hostPath: "/etc/kubernetes/pki/ca" trigger: - systemctl stop kube-apiserver.service - httpsCheck: 127.0.0.1:6443 keys: - name: system:kube-apiserver-sa - host_path: /etc/kubernetes/pki/certs/kube-apiserver/ # join(host_path,name) + hostPath: /etc/kubernetes/pki/certs/kube-apiserver/ # join(hostPath,name) privateKey: # добавить возможность менять тип и сайз algorithm: RSA encoding: PKCS1 size: 2048 - public: true # если false генерил локально, true генерил локально и пушил в vault + public: true # если false генерил локально, true генерил локально и пушил в vault vault: - kv: + kv: path: "clusters/${cluster_name}/kv" From fb0d937be89340d0500deb07cb378594c57131ae Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Tue, 23 Aug 2022 18:57:51 +0300 Subject: [PATCH 098/220] =?UTF-8?q?feature/FD-7=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D1=8F=D0=B5=D1=82=20=D1=84=D0=B0=D0=B9=D0=BB=20?= =?UTF-8?q?=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=82=D1=83=D1=80=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example.struct.yaml | 78 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 example.struct.yaml diff --git a/example.struct.yaml b/example.struct.yaml new file mode 100644 index 0000000..6fdbc5c --- /dev/null +++ b/example.struct.yaml @@ -0,0 +1,78 @@ +--- +global: # блок описывает базовую конфигурацию key-keeper + vault: # блок описывает базовый конфиг Vault + serever: string # rename $address (адрес волта) + caBundle: string # new (сертификат для подключения к волту - при http не должен фигурировать) + tlsInsecure: bool # new при указании тру скипать ssl верификацию + auth: # блок авторизации в Vault + bootstrap: # блок авторизации в Vault по бутстрап токену + tokenPath: string # rename $bootstrap_token + appRole: # блок авторизации в Vault по аппроли + name: string # rename $approle_name + path: string # rename $approle_path + roleIdPath: string # rename $local_path_to_role_id + secretIdPath: string # rename $local_path_to_secret_id + kv: # блок описывает базовый KV + path: string # блок описывает базовый путь KV + +issuers: # Описывает список доступных issuers + - name: string # Имя issuer + vault: # Все переменные global.Vault.* могут быть переопределены тут в блоке vault + role: # Блок описывающий роль волта + name: string # альтернатива блоку csr[*].role + path: string # альтернатива блоку csr[*].cert_path + intermediate: # Альтернатива блоку certificates.intermediate_ca + rootPath: string # Путь к root CA + exportedKey: bool # запрашивать приватный ключ или нет + generate: bool # генерить ЦА или запросить существующий CA + serever: string # rename $address (адрес волта) + caBundle: string # new (сертификат для подключения к волту - при http не должен фигурировать) + tlsInsecure: bool # new при указании тру скипать ssl верификацию + auth: # блок авторизации в Vault + bootstrap: # блок авторизации в Vault по бутстрап токену + tokenPath: string # rename $bootstrap_token + appRole: # блок авторизации в Vault по аппроли + name: string # rename $approle_name + path: string # rename $approle_path + roleIdPath: string # rename $local_path_to_role_id + secretIdPath: string # rename $local_path_to_secret_id + +certificates: # Описывает список доступных certificates + - name: string # Имя certificate + spec: # блок описывающий certificate + duration: string # на какой промежуток времени заказывается сертификат + renewBefore: string # за сколько до истечения надо перевыпустить + subject: # блок описывающий принадлежность certificate + countries: # Countries to be used on the Certificate. + localities: # Cities to be used on the Certificate. + organizationalUnits: # Organizational Units to be used on the Certificate. + organizations: # Organizations to be used on the Certificate. + postalCodes: # Postal codes to be used on the Certificate. + provinces: # State/Provinces to be used on the Certificate. + serialNumber: # Serial number to be used on the Certificate + streetAddresses: # Street addresses to be used on the Certificate. + commonName: string # CommonName is the common name as specified on the DER encoded CSR. If specified, this value must also be present in `dnsNames` or `ipAddresses`. This field must match the corresponding field on the DER encoded CSR. + privateKey: # Options to control private keys used for the Certificate. + algorithm: string # Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either `RSA`,`Ed25519` or `ECDSA` If `algorithm` is specified and `size` is not provided, key size of 256 will be used for `ECDSA` key algorithm and key size of 2048 will be used for `RSA` key algorithm. key size is ignored when using the `Ed25519` key algorithm. + encoding: string # The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 and PKCS#8, respectively. Defaults to `PKCS1` if not specified. + size: intager # Size is the key bit size of the corresponding private key for this certificate. If `algorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified. If `algorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, and will default to `256` if not specified. If `algorithm` is set to `Ed25519`, Size is ignored. No other values are allowed. + usages: list of strings # Usages is the set of x509 usages that are requested for the certificate. Defaults to `digital signature` and `key encipherment` if not specified. + dnsNames: list of strings # List of DNSNames that this solver will be used to solve. If specified and a match is found, a dnsNames selector will take precedence over a dnsZones selector. If multiple solvers match with the same dnsNames value, the solver with the most matching labels in matchLabels will be selected. If neither has more matches, the solver defined earlier in the list will be selected. + ipAddresses: list of strings # IPAddresses is a list of IP addresses that should be included as part of the Order validation process. This field must match the corresponding field on the DER encoded CSR. + issuerRef: # IssuerRef references a properly configured ACME-type Issuer which should be used to create this Order. If the Issuer does not exist, processing will be retried. If the Issuer is not an 'ACME' Issuer, an error will be returned and the Order will be marked as failed. + name: string # Имя вызываемого ISSUER + isCa: bool # IsCA will request to mark the certificate as valid for certificate signing when submitting to the issuer. This will automatically add the `cert sign` usage to the list of `usages`. + hostPathCert: string # путь, где будет размещен секрет по маске ${hostPathCert}/${certName} + trigger: list of strings # список bash команд которые применятся после обновления сертификата + +keys: # Описывает список доступных keys + - name: # Имя key + host_path: string # путь, где будет размещен секрет по маске ${hostPathCert}/${keyName} + privateKey: # Options to control private keys used for the Certificate. + algorithm: string # Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either `RSA`,`Ed25519` or `ECDSA` If `algorithm` is specified and `size` is not provided, key size of 256 will be used for `ECDSA` key algorithm and key size of 2048 will be used for `RSA` key algorithm. key size is ignored when using the `Ed25519` key algorithm. + encoding: string # The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 and PKCS#8, respectively. Defaults to `PKCS1` if not specified. + size: intager # Size is the key bit size of the corresponding private key for this certificate. If `algorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified. If `algorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, and will default to `256` if not specified. If `algorithm` is set to `Ed25519`, Size is ignored. No other values are allowed. + public: true # если false генерил локально, true генерил локально и пушил в vault + vault: # блок описывает базовый конфиг Vault + kv: # блок описывает базовый KV + path: string # блок описывает базовый путь KV From 1581c2bb53ba0a388de9b9159abed60b2ea8dda2 Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Tue, 23 Aug 2022 19:08:05 +0300 Subject: [PATCH 099/220] =?UTF-8?q?feture/FD-7=20=D1=84=D0=B8=D0=BA=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example.struct.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/example.struct.yaml b/example.struct.yaml index 6fdbc5c..c533e1c 100644 --- a/example.struct.yaml +++ b/example.struct.yaml @@ -43,14 +43,14 @@ certificates: # Описывает список дос duration: string # на какой промежуток времени заказывается сертификат renewBefore: string # за сколько до истечения надо перевыпустить subject: # блок описывающий принадлежность certificate - countries: # Countries to be used on the Certificate. - localities: # Cities to be used on the Certificate. - organizationalUnits: # Organizational Units to be used on the Certificate. - organizations: # Organizations to be used on the Certificate. - postalCodes: # Postal codes to be used on the Certificate. - provinces: # State/Provinces to be used on the Certificate. - serialNumber: # Serial number to be used on the Certificate - streetAddresses: # Street addresses to be used on the Certificate. + countries: string # Countries to be used on the Certificate. + localities: string # Cities to be used on the Certificate. + organizationalUnits: string # Organizational Units to be used on the Certificate. + organizations: string # Organizations to be used on the Certificate. + postalCodes: string # Postal codes to be used on the Certificate. + provinces: string # State/Provinces to be used on the Certificate. + serialNumber: string # Serial number to be used on the Certificate + streetAddresses: string # Street addresses to be used on the Certificate. commonName: string # CommonName is the common name as specified on the DER encoded CSR. If specified, this value must also be present in `dnsNames` or `ipAddresses`. This field must match the corresponding field on the DER encoded CSR. privateKey: # Options to control private keys used for the Certificate. algorithm: string # Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either `RSA`,`Ed25519` or `ECDSA` If `algorithm` is specified and `size` is not provided, key size of 256 will be used for `ECDSA` key algorithm and key size of 2048 will be used for `RSA` key algorithm. key size is ignored when using the `Ed25519` key algorithm. From 35db6c78c4748b708637b287b47c1c1ea2ceac9c Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Tue, 23 Aug 2022 19:13:00 +0300 Subject: [PATCH 100/220] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example.struct.yaml | 54 ++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/example.struct.yaml b/example.struct.yaml index c533e1c..f4f7ed8 100644 --- a/example.struct.yaml +++ b/example.struct.yaml @@ -37,33 +37,33 @@ issuers: # Описывает список дос roleIdPath: string # rename $local_path_to_role_id secretIdPath: string # rename $local_path_to_secret_id -certificates: # Описывает список доступных certificates - - name: string # Имя certificate - spec: # блок описывающий certificate - duration: string # на какой промежуток времени заказывается сертификат - renewBefore: string # за сколько до истечения надо перевыпустить - subject: # блок описывающий принадлежность certificate - countries: string # Countries to be used on the Certificate. - localities: string # Cities to be used on the Certificate. - organizationalUnits: string # Organizational Units to be used on the Certificate. - organizations: string # Organizations to be used on the Certificate. - postalCodes: string # Postal codes to be used on the Certificate. - provinces: string # State/Provinces to be used on the Certificate. - serialNumber: string # Serial number to be used on the Certificate - streetAddresses: string # Street addresses to be used on the Certificate. - commonName: string # CommonName is the common name as specified on the DER encoded CSR. If specified, this value must also be present in `dnsNames` or `ipAddresses`. This field must match the corresponding field on the DER encoded CSR. - privateKey: # Options to control private keys used for the Certificate. - algorithm: string # Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either `RSA`,`Ed25519` or `ECDSA` If `algorithm` is specified and `size` is not provided, key size of 256 will be used for `ECDSA` key algorithm and key size of 2048 will be used for `RSA` key algorithm. key size is ignored when using the `Ed25519` key algorithm. - encoding: string # The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 and PKCS#8, respectively. Defaults to `PKCS1` if not specified. - size: intager # Size is the key bit size of the corresponding private key for this certificate. If `algorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified. If `algorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, and will default to `256` if not specified. If `algorithm` is set to `Ed25519`, Size is ignored. No other values are allowed. - usages: list of strings # Usages is the set of x509 usages that are requested for the certificate. Defaults to `digital signature` and `key encipherment` if not specified. - dnsNames: list of strings # List of DNSNames that this solver will be used to solve. If specified and a match is found, a dnsNames selector will take precedence over a dnsZones selector. If multiple solvers match with the same dnsNames value, the solver with the most matching labels in matchLabels will be selected. If neither has more matches, the solver defined earlier in the list will be selected. - ipAddresses: list of strings # IPAddresses is a list of IP addresses that should be included as part of the Order validation process. This field must match the corresponding field on the DER encoded CSR. - issuerRef: # IssuerRef references a properly configured ACME-type Issuer which should be used to create this Order. If the Issuer does not exist, processing will be retried. If the Issuer is not an 'ACME' Issuer, an error will be returned and the Order will be marked as failed. - name: string # Имя вызываемого ISSUER - isCa: bool # IsCA will request to mark the certificate as valid for certificate signing when submitting to the issuer. This will automatically add the `cert sign` usage to the list of `usages`. - hostPathCert: string # путь, где будет размещен секрет по маске ${hostPathCert}/${certName} - trigger: list of strings # список bash команд которые применятся после обновления сертификата +certificates: # Описывает список доступных certificates + - name: string # Имя certificate + spec: # блок описывающий certificate + duration: string # на какой промежуток времени заказывается сертификат + renewBefore: string # за сколько до истечения надо перевыпустить + subject: # блок описывающий принадлежность certificate + countries: list of strings # Countries to be used on the Certificate. + localities: list of strings # Cities to be used on the Certificate. + organizationalUnits: list of strings # Organizational Units to be used on the Certificate. + organizations: list of strings # Organizations to be used on the Certificate. + postalCodes: list of strings # Postal codes to be used on the Certificate. + provinces: list of strings # State/Provinces to be used on the Certificate. + serialNumber: list of strings # Serial number to be used on the Certificate + streetAddresses: list of strings # Street addresses to be used on the Certificate. + commonName: string # CommonName is the common name as specified on the DER encoded CSR. If specified, this value must also be present in `dnsNames` or `ipAddresses`. This field must match the corresponding field on the DER encoded CSR. + privateKey: # Options to control private keys used for the Certificate. + algorithm: string # Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either `RSA`,`Ed25519` or `ECDSA` If `algorithm` is specified and `size` is not provided, key size of 256 will be used for `ECDSA` key algorithm and key size of 2048 will be used for `RSA` key algorithm. key size is ignored when using the `Ed25519` key algorithm. + encoding: string # The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 and PKCS#8, respectively. Defaults to `PKCS1` if not specified. + size: intager # Size is the key bit size of the corresponding private key for this certificate. If `algorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified. If `algorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, and will default to `256` if not specified. If `algorithm` is set to `Ed25519`, Size is ignored. No other values are allowed. + usages: list of strings # Usages is the set of x509 usages that are requested for the certificate. Defaults to `digital signature` and `key encipherment` if not specified. + dnsNames: list of strings # List of DNSNames that this solver will be used to solve. If specified and a match is found, a dnsNames selector will take precedence over a dnsZones selector. If multiple solvers match with the same dnsNames value, the solver with the most matching labels in matchLabels will be selected. If neither has more matches, the solver defined earlier in the list will be selected. + ipAddresses: list of strings # IPAddresses is a list of IP addresses that should be included as part of the Order validation process. This field must match the corresponding field on the DER encoded CSR. + issuerRef: # IssuerRef references a properly configured ACME-type Issuer which should be used to create this Order. If the Issuer does not exist, processing will be retried. If the Issuer is not an 'ACME' Issuer, an error will be returned and the Order will be marked as failed. + name: string # Имя вызываемого ISSUER + isCa: bool # IsCA will request to mark the certificate as valid for certificate signing when submitting to the issuer. This will automatically add the `cert sign` usage to the list of `usages`. + hostPathCert: string # путь, где будет размещен секрет по маске ${hostPathCert}/${certName} + trigger: list of strings # список bash команд которые применятся после обновления сертификата keys: # Описывает список доступных keys - name: # Имя key From 6f767d1e002b9c79801b16daf8d0147e1f6b5e29 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 29 Aug 2022 20:27:19 +0300 Subject: [PATCH 101/220] done --- README.md | 2 +- cmd/key-keeper/main.go | 2 +- config-struct-fraima.yaml | 79 +++++++++++ config-struct.yaml | 56 ++++++++ example.struct.yaml | 78 ----------- internal/config/config.go | 10 +- internal/config/types.go | 99 ++++++++++++++ internal/controller/config.go | 52 ------- internal/controller/config2.go | 66 --------- internal/controller/controller.go | 127 ++++++++++++------ internal/{ => issuer}/vault/store.go | 0 internal/{ => issuer}/vault/vault.go | 48 ++++--- internal/resource/ca.go | 102 ++++++++++++++ internal/resource/csr.go | 33 ++--- .../resource/intermediate-ca-exported-key.go | 126 ----------------- internal/resource/intermediate-ca.go | 106 --------------- internal/resource/{rsa.go => key.go} | 53 +++++--- internal/resource/resource.go | 68 +++++----- internal/resource/root-ca.go | 56 -------- internal/resource/store.go | 24 ++++ 20 files changed, 562 insertions(+), 625 deletions(-) create mode 100644 config-struct-fraima.yaml create mode 100644 config-struct.yaml delete mode 100644 example.struct.yaml create mode 100644 internal/config/types.go delete mode 100644 internal/controller/config.go delete mode 100644 internal/controller/config2.go rename internal/{ => issuer}/vault/store.go (100%) rename internal/{ => issuer}/vault/vault.go (59%) create mode 100644 internal/resource/ca.go delete mode 100644 internal/resource/intermediate-ca-exported-key.go delete mode 100644 internal/resource/intermediate-ca.go rename internal/resource/{rsa.go => key.go} (54%) delete mode 100644 internal/resource/root-ca.go diff --git a/README.md b/README.md index 650ce70..ecdee8c 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ certificates: # Все сертификаты выпускаются в этих сейфах intermediate_ca: - common_name: "kubernetes" # CN - root_path_ca: "clusters/cluster-1/pki/root" # Путь к сейфу корневого CA + root_path_ca: "clusters/cluster-1/pki/root" cert_path: "clusters/cluster-1/pki/kubernetes" # Путь к сейфу Inermediate CA host_path: "/etc/kubernetes/pki/ca/root-ca" # Локальный путь, где будет размещен public / private keys exported_key: false # Этот флаг заказывает Inermediate типа internal/external (в отпут придет private-key или нет) diff --git a/cmd/key-keeper/main.go b/cmd/key-keeper/main.go index 5affb2d..ad0220d 100644 --- a/cmd/key-keeper/main.go +++ b/cmd/key-keeper/main.go @@ -11,7 +11,7 @@ import ( "github.com/fraima/key-keeper/internal/config" "github.com/fraima/key-keeper/internal/controller" "github.com/fraima/key-keeper/internal/resource" - "github.com/fraima/key-keeper/internal/vault" + "github.com/fraima/key-keeper/internal/issuer/vault" ) var ( diff --git a/config-struct-fraima.yaml b/config-struct-fraima.yaml new file mode 100644 index 0000000..efd4c47 --- /dev/null +++ b/config-struct-fraima.yaml @@ -0,0 +1,79 @@ +--- +global: # блок описывает базовую конфигурацию key-keeper + vault: # блок описывает базовый конфиг Vault + serever: string # rename $address (адрес волта) + caBundle: string # new (сертификат для подключения к волту - при http не должен фигурировать) + tlsInsecure: bool # new при указании тру скипать ssl верификацию + auth: # блок авторизации в Vault + bootstrap: # блок авторизации в Vault по бутстрап токену + tokenPath: string # rename $bootstrap_token + appRole: # блок авторизации в Vault по аппроли + name: string # rename $approle_name + path: string # rename $approle_path + roleIdPath: string # rename $local_path_to_role_id + secretIdPath: string # rename $local_path_to_secret_id + kv: # блок описывает базовый KV + path: string # блок описывает базовый путь KV + +issuers: # Описывает список доступных issuers + - name: string # Имя issuer + vault: # Все переменные global.Vault.* могут быть переопределены тут в блоке vault + role: # Блок описывающий роль волта + name: string # альтернатива блоку csr[*].role + path: string # альтернатива блоку csr[*].cert_path + intermediate: # Альтернатива блоку certificates.intermediate_ca + rootPath: string # Путь к root CA + exportedKey: bool # запрашивать приватный ключ или нет + generate: bool # генерить ЦА или запросить существующий CA + server: string # rename $address (адрес волта) + caBundle: string # new (сертификат для подключения к волту - при http не должен фигурировать) + tlsInsecure: bool # new при указании тру скипать ssl верификацию + auth: # блок авторизации в Vault + bootstrap: # блок авторизации в Vault по бутстрап токену + tokenPath: string # rename $bootstrap_token + appRole: # блок авторизации в Vault по аппроли + name: string # rename $approle_name + path: string # rename $approle_path + roleIdPath: string # rename $local_path_to_role_id + secretIdPath: string # rename $local_path_to_secret_id + +certificates: # Описывает список доступных certificates + - name: string # Имя certificate + issuerRef: # IssuerRef references a properly configured ACME-type Issuer which should be used to create this Order. If the Issuer does not exist, processing will be retried. If the Issuer is not an 'ACME' Issuer, an error will be returned and the Order will be marked as failed. + name: string # Имя вызываемого ISSUER + spec: # блок описывающий certificate + duration: string # на какой промежуток времени заказывается сертификат + renewBefore: string # за сколько до истечения надо перевыпустить + subject: # блок описывающий принадлежность certificate + countries: # Countries to be used on the Certificate. + localities: # Cities to be used on the Certificate. + organizationalUnits: # Organizational Units to be used on the Certificate. + organizations: # Organizations to be used on the Certificate. + postalCodes: # Postal codes to be used on the Certificate. + provinces: # State/Provinces to be used on the Certificate. + serialNumber: # Serial number to be used on the Certificate + streetAddresses: # Street addresses to be used on the Certificate. + commonName: string # CommonName is the common name as specified on the DER encoded CSR. If specified, this value must also be present in `dnsNames` or `ipAddresses`. This field must match the corresponding field on the DER encoded CSR. + privateKey: # Options to control private keys used for the Certificate. + algorithm: string # Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either `RSA`,`Ed25519` or `ECDSA` If `algorithm` is specified and `size` is not provided, key size of 256 will be used for `ECDSA` key algorithm and key size of 2048 will be used for `RSA` key algorithm. key size is ignored when using the `Ed25519` key algorithm. + encoding: string # The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 and PKCS#8, respectively. Defaults to `PKCS1` if not specified. + size: intager # Size is the key bit size of the corresponding private key for this certificate. If `algorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified. If `algorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, and will default to `256` if not specified. If `algorithm` is set to `Ed25519`, Size is ignored. No other values are allowed. + usages: list of strings # Usages is the set of x509 usages that are requested for the certificate. Defaults to `digital signature` and `key encipherment` if not specified. + dnsNames: list of strings # List of DNSNames that this solver will be used to solve. If specified and a match is found, a dnsNames selector will take precedence over a dnsZones selector. If multiple solvers match with the same dnsNames value, the solver with the most matching labels in matchLabels will be selected. If neither has more matches, the solver defined earlier in the list will be selected. + ipAddresses: list of strings # IPAddresses is a list of IP addresses that should be included as part of the Order validation process. This field must match the corresponding field on the DER encoded CSR. + isCa: bool # IsCA will request to mark the certificate as valid for certificate signing when submitting to the issuer. This will automatically add the `cert sign` usage to the list of `usages`. + hostPath: string # путь, где будет размещен секрет по маске ${hostPath}/${certName} + trigger: list of strings # список bash команд которые применятся после обновления сертификата + + +keys: # Описывает список доступных keys + - name: # Имя key + host_path: string # путь, где будет размещен секрет по маске ${hostPathCert}/${keyName} + privateKey: # Options to control private keys used for the Certificate. + algorithm: string # Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either `RSA`,`Ed25519` or `ECDSA` If `algorithm` is specified and `size` is not provided, key size of 256 will be used for `ECDSA` key algorithm and key size of 2048 will be used for `RSA` key algorithm. key size is ignored when using the `Ed25519` key algorithm. + encoding: string # The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 and PKCS#8, respectively. Defaults to `PKCS1` if not specified. + size: intager # Size is the key bit size of the corresponding private key for this certificate. If `algorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified. If `algorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, and will default to `256` if not specified. If `algorithm` is set to `Ed25519`, Size is ignored. No other values are allowed. + public: true # если false генерил локально, true генерил локально и пушил в vault + vault: # блок описывает базовый конфиг Vault + kv: # блок описывает базовый KV + path: string # блок описывает базовый путь KV diff --git a/config-struct.yaml b/config-struct.yaml new file mode 100644 index 0000000..db5292b --- /dev/null +++ b/config-struct.yaml @@ -0,0 +1,56 @@ +--- +issuers: # Описывает список доступных issuers + - name: string # Имя issuer + vault: # Все переменные global.Vault.* могут быть переопределены тут в блоке vault + server: string # rename $address (адрес волта) + auth: # блок авторизации в Vault + caBundle: string # new (сертификат для подключения к волту - при http не должен фигурировать) + tlsInsecure: bool # new при указании тру скипать ssl верификацию + bootstrap: # блок авторизации в Vault по бутстрап токену + tokenPath: string # rename $bootstrap_token + appRole: # блок авторизации в Vault по аппроли + name: string # rename $approle_name + path: string # rename $approle_path + roleIDLocalPath: string # rename $local_path_to_role_id + secretIDLocalPath: string # rename $local_path_to_secret_id + timeout: string # строка формата "1s", таймаут для любого обращения к issuer + +certificates: # Описывает список доступных certificates + - name: string # Имя certificate + issuerRef: # IssuerRef references a properly configured ACME-type Issuer which should be used to create this Order. If the Issuer does not exist, processing will be retried. If the Issuer is not an 'ACME' Issuer, an error will be returned and the Order will be marked as failed. + name: string # Имя вызываемого ISSUER + isCa: bool # IsCA will request to mark the certificate as valid for certificate signing when submitting to the issuer. This will automatically add the `cert sign` usage to the list of `usages`. + spec: # блок описывающий certificate + commonName: string # CommonName is the common name as specified on the DER encoded CSR. If specified, this value must also be present in `dnsNames` or `ipAddresses`. This field must match the corresponding field on the DER encoded CSR. + subject: # блок описывающий принадлежность certificate + countries: list of string # Countries to be used on the Certificate. + localities: list of string # Cities to be used on the Certificate. + organizationalUnits: list of string # Organizational Units to be used on the Certificate. + organizations: list of string # Organizations to be used on the Certificate. + postalCodes: list of string # Postal codes to be used on the Certificate. + provinces: list of string # State/Provinces to be used on the Certificate. + serialNumber: string # Serial number to be used on the Certificate + streetAddresses: list of string # Street addresses to be used on the Certificate. + privateKey: # Options to control private keys used for the Certificate. + algorithm: string # Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either `RSA`,`Ed25519` or `ECDSA` If `algorithm` is specified and `size` is not provided, key size of 256 will be used for `ECDSA` key algorithm and key size of 2048 will be used for `RSA` key algorithm. key size is ignored when using the `Ed25519` key algorithm. + encoding: string # The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 and PKCS#8, respectively. Defaults to `PKCS1` if not specified. + size: integer # Size is the key bit size of the corresponding private key for this certificate. If `algorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified. If `algorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, and will default to `256` if not specified. If `algorithm` is set to `Ed25519`, Size is ignored. No other values are allowed. + usages: list of string # Usages is the set of x509 usages that are requested for the certificate. Defaults to `digital signature` and `key encipherment` if not specified. + hostnames: list of string # List of DNSNames that this solver will be used to solve. If specified and a match is found, a dnsNames selector will take precedence over a dnsZones selector. If multiple solvers match with the same dnsNames value, the solver with the most matching labels in matchLabels will be selected. If neither has more matches, the solver defined earlier in the list will be selected. + ipAddresses: list of string # IPAddresses is a list of IP addresses that should be included as part of the Order validation process. This field must match the corresponding field on the DER encoded CSR. + ttl: string # на какой промежуток времени заказывается сертификат + hostPath: string # путь, где будет размещен секрет по маске ${hostPathCert}/${certName} + vaultPath: string # Путь к сейфу Inermediate CA где будет заказан сертификат + vaultRole: string + vaultRootCAPath: string # Путь к сейфу корневого CA + trigger: list of string # список bash команд которые применятся после обновления сертификата + renewBefore: string # за сколько до истечения надо перевыпустить + +keys: # Описывает список доступных keys + - name: # Имя key + privateKey: # Options to control private keys used for the Certificate. + algorithm: string # Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either `RSA`,`Ed25519` or `ECDSA` If `algorithm` is specified and `size` is not provided, key size of 256 will be used for `ECDSA` key algorithm and key size of 2048 will be used for `RSA` key algorithm. key size is ignored when using the `Ed25519` key algorithm. + encoding: string # The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 and PKCS#8, respectively. Defaults to `PKCS1` if not specified. + size: integer # Size is the key bit size of the corresponding private key for this certificate. If `algorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified. If `algorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, and will default to `256` if not specified. If `algorithm` is set to `Ed25519`, Size is ignored. No other values are allowed. + public: true # если false генерил локально, true генерил локально и пушил в vault + hostPath: string # путь, где будет размещен секрет по маске ${hostPathCert}/${keyName} diff --git a/example.struct.yaml b/example.struct.yaml deleted file mode 100644 index 6fdbc5c..0000000 --- a/example.struct.yaml +++ /dev/null @@ -1,78 +0,0 @@ ---- -global: # блок описывает базовую конфигурацию key-keeper - vault: # блок описывает базовый конфиг Vault - serever: string # rename $address (адрес волта) - caBundle: string # new (сертификат для подключения к волту - при http не должен фигурировать) - tlsInsecure: bool # new при указании тру скипать ssl верификацию - auth: # блок авторизации в Vault - bootstrap: # блок авторизации в Vault по бутстрап токену - tokenPath: string # rename $bootstrap_token - appRole: # блок авторизации в Vault по аппроли - name: string # rename $approle_name - path: string # rename $approle_path - roleIdPath: string # rename $local_path_to_role_id - secretIdPath: string # rename $local_path_to_secret_id - kv: # блок описывает базовый KV - path: string # блок описывает базовый путь KV - -issuers: # Описывает список доступных issuers - - name: string # Имя issuer - vault: # Все переменные global.Vault.* могут быть переопределены тут в блоке vault - role: # Блок описывающий роль волта - name: string # альтернатива блоку csr[*].role - path: string # альтернатива блоку csr[*].cert_path - intermediate: # Альтернатива блоку certificates.intermediate_ca - rootPath: string # Путь к root CA - exportedKey: bool # запрашивать приватный ключ или нет - generate: bool # генерить ЦА или запросить существующий CA - serever: string # rename $address (адрес волта) - caBundle: string # new (сертификат для подключения к волту - при http не должен фигурировать) - tlsInsecure: bool # new при указании тру скипать ssl верификацию - auth: # блок авторизации в Vault - bootstrap: # блок авторизации в Vault по бутстрап токену - tokenPath: string # rename $bootstrap_token - appRole: # блок авторизации в Vault по аппроли - name: string # rename $approle_name - path: string # rename $approle_path - roleIdPath: string # rename $local_path_to_role_id - secretIdPath: string # rename $local_path_to_secret_id - -certificates: # Описывает список доступных certificates - - name: string # Имя certificate - spec: # блок описывающий certificate - duration: string # на какой промежуток времени заказывается сертификат - renewBefore: string # за сколько до истечения надо перевыпустить - subject: # блок описывающий принадлежность certificate - countries: # Countries to be used on the Certificate. - localities: # Cities to be used on the Certificate. - organizationalUnits: # Organizational Units to be used on the Certificate. - organizations: # Organizations to be used on the Certificate. - postalCodes: # Postal codes to be used on the Certificate. - provinces: # State/Provinces to be used on the Certificate. - serialNumber: # Serial number to be used on the Certificate - streetAddresses: # Street addresses to be used on the Certificate. - commonName: string # CommonName is the common name as specified on the DER encoded CSR. If specified, this value must also be present in `dnsNames` or `ipAddresses`. This field must match the corresponding field on the DER encoded CSR. - privateKey: # Options to control private keys used for the Certificate. - algorithm: string # Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either `RSA`,`Ed25519` or `ECDSA` If `algorithm` is specified and `size` is not provided, key size of 256 will be used for `ECDSA` key algorithm and key size of 2048 will be used for `RSA` key algorithm. key size is ignored when using the `Ed25519` key algorithm. - encoding: string # The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 and PKCS#8, respectively. Defaults to `PKCS1` if not specified. - size: intager # Size is the key bit size of the corresponding private key for this certificate. If `algorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified. If `algorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, and will default to `256` if not specified. If `algorithm` is set to `Ed25519`, Size is ignored. No other values are allowed. - usages: list of strings # Usages is the set of x509 usages that are requested for the certificate. Defaults to `digital signature` and `key encipherment` if not specified. - dnsNames: list of strings # List of DNSNames that this solver will be used to solve. If specified and a match is found, a dnsNames selector will take precedence over a dnsZones selector. If multiple solvers match with the same dnsNames value, the solver with the most matching labels in matchLabels will be selected. If neither has more matches, the solver defined earlier in the list will be selected. - ipAddresses: list of strings # IPAddresses is a list of IP addresses that should be included as part of the Order validation process. This field must match the corresponding field on the DER encoded CSR. - issuerRef: # IssuerRef references a properly configured ACME-type Issuer which should be used to create this Order. If the Issuer does not exist, processing will be retried. If the Issuer is not an 'ACME' Issuer, an error will be returned and the Order will be marked as failed. - name: string # Имя вызываемого ISSUER - isCa: bool # IsCA will request to mark the certificate as valid for certificate signing when submitting to the issuer. This will automatically add the `cert sign` usage to the list of `usages`. - hostPathCert: string # путь, где будет размещен секрет по маске ${hostPathCert}/${certName} - trigger: list of strings # список bash команд которые применятся после обновления сертификата - -keys: # Описывает список доступных keys - - name: # Имя key - host_path: string # путь, где будет размещен секрет по маске ${hostPathCert}/${keyName} - privateKey: # Options to control private keys used for the Certificate. - algorithm: string # Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either `RSA`,`Ed25519` or `ECDSA` If `algorithm` is specified and `size` is not provided, key size of 256 will be used for `ECDSA` key algorithm and key size of 2048 will be used for `RSA` key algorithm. key size is ignored when using the `Ed25519` key algorithm. - encoding: string # The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 and PKCS#8, respectively. Defaults to `PKCS1` if not specified. - size: intager # Size is the key bit size of the corresponding private key for this certificate. If `algorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified. If `algorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, and will default to `256` if not specified. If `algorithm` is set to `Ed25519`, Size is ignored. No other values are allowed. - public: true # если false генерил локально, true генерил локально и пушил в vault - vault: # блок описывает базовый конфиг Vault - kv: # блок описывает базовый KV - path: string # блок описывает базовый путь KV diff --git a/internal/config/config.go b/internal/config/config.go index d6d474d..cdde7e7 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -8,8 +8,6 @@ import ( "go.uber.org/zap" "gopkg.in/yaml.v3" - - "github.com/fraima/key-keeper/internal/controller" ) type config struct { @@ -34,7 +32,7 @@ func New(configDir, configNameLayout string) (*config, error) { } // GetNewConfig return new config from config dir. -func (s *config) GetNewConfig() (cfgs []controller.Config, err error) { +func (s *config) GetNewConfig() (newCfg Config, err error) { list, err := s.getNewConfigFiles() if err != nil { return @@ -46,13 +44,15 @@ func (s *config) GetNewConfig() (cfgs []controller.Config, err error) { zap.L().Error("read config file", zap.String("path", path), zap.Error(err)) continue } - var cfg controller.Config + var cfg Config if err = yaml.Unmarshal(data, cfg); err != nil { zap.L().Error("unmurshal config file", zap.String("path", path), zap.Error(err)) continue } - cfgs = append(cfgs, cfg) + newCfg.Issueres = append(newCfg.Issueres, cfg.Issueres...) + newCfg.Resource.Certificates = append(newCfg.Resource.Certificates, cfg.Resource.Certificates...) + newCfg.Resource.Keys = append(newCfg.Resource.Keys, cfg.Resource.Keys...) s.oldConfig[path] = struct{}{} } diff --git a/internal/config/types.go b/internal/config/types.go new file mode 100644 index 0000000..eb30d4b --- /dev/null +++ b/internal/config/types.go @@ -0,0 +1,99 @@ +package config + +import "time" + +type Config struct { + Issueres []Issuer `yaml:"issueres"` + Resource Resources `yaml:",inline"` +} + +type Issuer struct { + Name string `yaml:"name"` + Vault Vault `yaml:"vault"` +} + +type Resources struct { + Certificates []Certificate `yaml:"certificate"` + Keys []Key `yaml:"key"` +} + +type Certificate struct { + Name string `yaml:"name"` + IssuerRef IssuerRef `yaml:"issuerRef"` + IsCA bool `yaml:"isCa"` + Spec Spec `yaml:"spec"` + HostPath string `yaml:"hostPath"` + VaultPath string `yaml:"vaultPath"` + VaultRole string `yaml:"vaultRole"` + VaultRootCAPath string `yaml:"vaulRrootCAPath"` + Trigger []string `yaml:"trigger"` + RenewBefore time.Duration `yaml:"renewBefore" ` +} + +type Key struct { + Name string `yaml:"name"` + IssuerRef IssuerRef `yaml:"issuerRef"` + PrivateKey PrivateKey `yaml:"privateKey"` + Public bool `yaml:"public"` + HostPath string `yaml:"hostPath"` +} + +type IssuerRef struct { + Name string `yaml:"name"` +} + +type Vault struct { + Server string `yaml:"address"` + Auth Auth `yaml:"auth"` + KV KV `yaml:"kv"` + Timeout time.Duration `yaml:"timeout"` +} + +type Auth struct { + TLSInsecure bool `yaml:"tlsInsecure"` + CABundle string `yaml:"caBundle"` + Bootstrap Bootstrap `yaml:"bootstrap"` + AppRole AppRole `yaml:"appRole"` +} + +type KV struct { + Path string `yaml:"paths"` +} + +type Bootstrap struct { + Token string `yaml:"token"` +} + +type AppRole struct { + Name string `yaml:"name"` + Path string `yaml:"path"` + RoleIDLocalPath string `yaml:"roleIDLocalPath"` + SecretIDLocalPath string `yaml:"secretIDLocalPath"` +} + +type Spec struct { + CommonName string `yaml:"commonName"` + Subject Subject `yaml:"subject"` + PrivateKey PrivateKey `yaml:"privateKey"` + Usages []string `yaml:"usages"` + Hostnames []string `yaml:"hostnames"` + IPAddresses []string `yaml:"ipAddresses"` + TTL string `yaml:"ttl"` +} + +type Subject struct { + Countries []string `yaml:"countries"` + Localities []string `yaml:"localities"` + OrganizationalUnits []string `yaml:"organizationalUnits"` + Organizations []string `yaml:"organizations"` + PostalCodes []string `yaml:"postalCodes"` + Provinces []string `yaml:"provinces"` + SerialNumber string `yaml:"serialNumber"` + StreetAddresses []string `yaml:"streetAddresses"` +} + +type PrivateKey struct { + Algorithm string `yaml:"algorithm"` + Encoding string `yaml:"encoding"` + Size int `yaml:"size"` +} diff --git a/internal/controller/config.go b/internal/controller/config.go deleted file mode 100644 index 0effa7c..0000000 --- a/internal/controller/config.go +++ /dev/null @@ -1,52 +0,0 @@ -package controller - -import ( - "time" -) - -type Config struct { - Vault VaultConfig `yaml:"vault"` - Recource RecourceConfig `yaml:",inline"` -} - -type Certificates struct { - VaultKV string `yaml:"vault_kv"` - ReissueInterval time.Duration `yaml:"reissue_interval"` - RootCA []RootCA `yaml:"root_ca,omitempty"` - IntermediateCA []IntermediateCA `yaml:"intermediate_ca,omitempty"` - CSR []CSR `yaml:"csr,omitempty"` -} - -type RootCA struct { - CommonName string `yaml:"common_name"` - RootPathCA string `yaml:"root_path_ca"` -} - -type IntermediateCA struct { - CommonName string `yaml:"common_name"` - RootPathCA string `yaml:"root_path_ca"` - CertPath string `yaml:"cert_path"` - Generate bool `yaml:"generate"` - ExportedKey bool `yaml:"exported_key"` - HostPath string `yaml:"host_path"` -} - -type CSR struct { - CommonName string `yaml:"common_name"` - Hosts []string `yaml:"hosts"` - IPs []string `yaml:"ips"` - CertPath string `yaml:"cert_path"` - Role string `yaml:"role"` - HostPath string `yaml:"host_path"` - Trigger []string `yaml:"trigger"` -} - -type Keys struct { - VaultKV string `yaml:"vault_kv"` - RSA []RSA `yaml:"rsa"` -} - -type RSA struct { - Name string `yaml:"name"` - HostPath string `yaml:"host_path"` -} diff --git a/internal/controller/config2.go b/internal/controller/config2.go deleted file mode 100644 index 287bc5f..0000000 --- a/internal/controller/config2.go +++ /dev/null @@ -1,66 +0,0 @@ -package controller - -import "time" - -type GlobalConfig struct{} - -type IssuerConfig struct { - Issuers []issuer `yaml:",inline"` -} - -type RecourceConfig struct { - Certificates []Certificate `json:"certificates"` - Keys Keys `json:"keys"` -} - -type issuer struct { - Name string `yaml:"name"` - Vault VaultConfig `yaml:""` -} - -// VaultConfig for work with vault -type VaultConfig struct { - Server string `yaml:"address"` - CABundle string `yaml:"caBundle"` - Auth struct { - Bootstrap struct { - Token string `yaml:"token"` - } `yaml:"bootstrap"` - AppRole struct { - Name string `yaml:"name"` - Path string `yaml:"path"` - RoleIDLocalPath string `yaml:"roleIDLocalPath"` - SecretIDLocalPath string `yaml:"secretIDLocalPath"` - } - } `yaml:"auth"` - RequestTimeout time.Duration `yaml:"request_timeout"` -} - -type Certificate struct { - Name string `yaml:"name"` - Spec certificateSpec `yaml:"spec"` - HostPath string `yaml:"hostPath"` - Trigger []string `yaml:"trigger"` -} - -type certificateSpec struct { - CommonName string `yaml:"commonName"` - Subject struct { - Organizations []string `yaml:"organizations"` - Ous []string `yaml:"ous"` - Countries []string `yaml:"countries"` - } `yaml:"subject"` - PrivateKey struct { - Algorithm string `yaml:"algorithm"` - Encoding string `yaml:"encoding"` - Size int `yaml:"size"` - } `yaml:"privateKey"` - Usages []string `yaml:"usages"` - DNSNames []string `yaml:"dnsNames"` - IPAddresses []string `yaml:"ipAddresses"` - IssuerRef struct { - Name string `yaml:"name"` - } `yaml:"issuerRef"` - Lifespan string `yaml:"lifespan"` - RenewBefore time.Duration `yaml:"renewBefore"` -} diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 0435a09..998b9fc 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -1,87 +1,138 @@ package controller import ( + "errors" "fmt" "sync" "time" + "github.com/fraima/key-keeper/internal/config" "go.uber.org/zap" ) -type config interface { - GetNewConfig() (cfgs []Config, err error) +type Config interface { + GetNewConfig() (cfgs config.Config, err error) } type Vault interface { Write(path string, data map[string]interface{}) (map[string]interface{}, error) Read(path string) (map[string]interface{}, error) - Put(mountPath, secretePath string, data map[string]interface{}) error - Get(mountPath, secretePath string) (map[string]interface{}, error) + Put(secretePath string, data map[string]interface{}) error + Get(secretePath string) (map[string]interface{}, error) } type Resource interface { + Add(r config.Resources) Check() } type controller struct { - config config - vaultConnector func(cfg VaultConfig) (Vault, error) + config Config + vaultConnector func(cfg config.Vault) (Vault, error) - resourcePreparing func(vault Vault, cfg RecourceConfig) Resource - lock sync.RWMutex - resources []Resource + newResource func(vault Vault) Resource + resource sync.Map } func New( - config config, - vaultConnector func(cfg VaultConfig) (Vault, error), - resourcePreparing func(vault Vault, cfg RecourceConfig) Resource, + config Config, + vaultConnector func(cfg config.Vault) (Vault, error), + newResource func(vault Vault) Resource, ) *controller { return &controller{ - config: config, - vaultConnector: vaultConnector, - resourcePreparing: resourcePreparing, + config: config, + vaultConnector: vaultConnector, + newResource: newResource, } } // Start controller of key-keeper. func (s *controller) Start() { - go func() { - t := time.NewTicker(30 * time.Second) - defer t.Stop() - for range t.C { - if err := s.getNewRecource(); err != nil { - zap.L().Error("runtime", zap.Error(err)) - } - } - }() - t := time.NewTicker(time.Hour) defer t.Stop() for range t.C { - s.lock.RLock() - for _, r := range s.resources { - r.Check() + s.resource.Range(func(key, value any) bool { + value.(Resource).Check() + return true + }) + } +} + +func (s *controller) RefreshResource() { + t := time.NewTicker(30 * time.Second) + defer t.Stop() + for range t.C { + if err := s.getNewResource(); err != nil { + zap.L().Error("refresh resources", zap.Error(err)) } - s.lock.RUnlock() } } -func (s *controller) getNewRecource() error { - cfgList, err := s.config.GetNewConfig() +func (s *controller) getNewResource() error { + cfg, err := s.config.GetNewConfig() if err != nil { return fmt.Errorf("get new configs: %w", err) } - for _, cfg := range cfgList { - vaultConnect, err := s.vaultConnector(cfg.Vault) + for _, vaultCfg := range cfg.Issueres { + // TODO: что делать если приходит несколько issuer с одинаковыми именами + _, isExist := s.resource.Load(vaultCfg.Name) + if isExist { + zap.L().Warn( + "preparing resource", + zap.String("issuer_name", vaultCfg.Name), + zap.String("step", "connect to issuer"), + zap.Error(errors.New("issuer is exist")), + ) + continue + } + vaultConnection, err := s.vaultConnector(vaultCfg.Vault) if err != nil { - zap.L().Error("connect to vault", zap.Error(err)) + zap.L().Error( + "preparing resource", + zap.String("issuer_name", vaultCfg.Name), + zap.String("step", "connect to issuer"), + zap.Error(err), + ) + continue } - r := s.resourcePreparing(vaultConnect, cfg.Recource) - s.lock.Lock() - s.resources = append(s.resources, r) - s.lock.Unlock() + + r := s.newResource(vaultConnection) + s.resource.Store(vaultCfg.Name, r) } + + resources := s.separateResources(cfg.Resource) + for issuerName, resourceCfg := range resources { + r, isExist := s.resource.Load(issuerName) + if !isExist { + zap.L().Warn( + "preparing resource", + zap.String("issuer_name", issuerName), + zap.String("step", "add recource"), + zap.Error(errors.New("issuer is not exist")), + ) + continue + } + r.(Resource).Add(resourceCfg) + } + return nil } + +func (s *controller) separateResources(cfg config.Resources) map[string]config.Resources { + // TODO: что делать если приходит несколько ресурсов с одинаковыми именами для одного issuer + r := make(map[string]config.Resources) + + for _, cert := range cfg.Certificates { + resources := r[cert.IssuerRef.Name] + resources.Certificates = append(resources.Certificates, cert) + r[cert.IssuerRef.Name] = resources + } + + for _, key := range cfg.Keys { + resources := r[key.IssuerRef.Name] + resources.Keys = append(resources.Keys, key) + r[key.IssuerRef.Name] = resources + } + return r +} diff --git a/internal/vault/store.go b/internal/issuer/vault/store.go similarity index 100% rename from internal/vault/store.go rename to internal/issuer/vault/store.go diff --git a/internal/vault/vault.go b/internal/issuer/vault/vault.go similarity index 59% rename from internal/vault/vault.go rename to internal/issuer/vault/vault.go index bef7978..cc2975b 100644 --- a/internal/vault/vault.go +++ b/internal/issuer/vault/vault.go @@ -9,19 +9,21 @@ import ( "github.com/hashicorp/vault/api" auth "github.com/hashicorp/vault/api/auth/approle" + "github.com/fraima/key-keeper/internal/config" "github.com/fraima/key-keeper/internal/controller" ) type vault struct { - cli *api.Client + cli *api.Client + kvMountPath string } -func Connect(cfg controller.VaultConfig) (controller.Vault, error) { +func Connect(cfg config.Vault) (controller.Vault, error) { client, err := api.NewClient( &api.Config{ Address: cfg.Server, HttpClient: &http.Client{ - Timeout: cfg.RequestTimeout, + Timeout: cfg.Timeout, }, }, ) @@ -29,16 +31,22 @@ func Connect(cfg controller.VaultConfig) (controller.Vault, error) { return nil, fmt.Errorf("new vault client: %w", err) } client.SetToken(cfg.Auth.Bootstrap.Token) + if !cfg.Auth.TLSInsecure { + if err = client.CloneConfig().ConfigureTLS(&api.TLSConfig{CACert: cfg.Auth.CABundle}); err != nil { + return nil, fmt.Errorf("configurate tls: %w", err) + } + } s := &vault{ - cli: client, + cli: client, + kvMountPath: cfg.KV.Path, } - roleID, err := s.roleID(cfg) + roleID, err := s.roleID(cfg.Auth.AppRole) if err != nil { return nil, fmt.Errorf("get role id: %w", err) } - secretID, err := s.secretID(cfg) + secretID, err := s.secretID(cfg.Auth.AppRole) if err != nil { return nil, fmt.Errorf("get secret id: %w", err) } @@ -64,11 +72,11 @@ func Connect(cfg controller.VaultConfig) (controller.Vault, error) { return s, nil } -func (s *vault) roleID(cfg controller.VaultConfig) (string, error) { - path := path.Join("auth", cfg.Auth.AppRole.Path, "role", cfg.Auth.AppRole.Name, "role-id") +func (s *vault) roleID(appRole config.AppRole) (string, error) { + path := path.Join("auth", appRole.Path, "role", appRole.Name, "role-id") approle, err := s.Read(path) if err != nil { - if roleID, rErr := readFromFile(cfg.Auth.AppRole.RoleIDLocalPath); rErr == nil { + if roleID, rErr := readFromFile(appRole.RoleIDLocalPath); rErr == nil { return string(roleID), nil } return "", fmt.Errorf("read role_id for path: %s : %w", path, err) @@ -81,17 +89,17 @@ func (s *vault) roleID(cfg controller.VaultConfig) (string, error) { if !ok { return "", fmt.Errorf("not found role_id") } - if err = writeToFile(cfg.Auth.AppRole.RoleIDLocalPath, roleID.(string)); err != nil { - return "", fmt.Errorf("save role id path: %s id: %w", cfg.Auth.AppRole.RoleIDLocalPath, err) + if err = writeToFile(appRole.RoleIDLocalPath, roleID.(string)); err != nil { + return "", fmt.Errorf("save role id path: %s id: %w", appRole.RoleIDLocalPath, err) } return roleID.(string), err } -func (s *vault) secretID(cfg controller.VaultConfig) (string, error) { - path := path.Join("auth", cfg.Auth.AppRole.Path, "role", cfg.Auth.AppRole.Name, "secret-id") +func (s *vault) secretID(appRole config.AppRole) (string, error) { + path := path.Join("auth", appRole.Path, "role", appRole.Name, "secret-id") approle, err := s.Write(path, nil) if err != nil { - if secretID, rErr := readFromFile(cfg.Auth.AppRole.SecretIDLocalPath); rErr == nil { + if secretID, rErr := readFromFile(appRole.SecretIDLocalPath); rErr == nil { return string(secretID), nil } return "", fmt.Errorf("read secrete_id for path: %s : %w", path, err) @@ -105,8 +113,8 @@ func (s *vault) secretID(cfg controller.VaultConfig) (string, error) { return "", fmt.Errorf("not found secrete_id") } - if err = writeToFile(cfg.Auth.AppRole.SecretIDLocalPath, secretID.(string)); err != nil { - return "", fmt.Errorf("save secret id path: %s id: %w", cfg.Auth.AppRole.SecretIDLocalPath, err) + if err = writeToFile(appRole.SecretIDLocalPath, secretID.(string)); err != nil { + return "", fmt.Errorf("save secret id path: %s id: %w", appRole.SecretIDLocalPath, err) } return secretID.(string), err } @@ -130,14 +138,14 @@ func (s *vault) Write(path string, data map[string]interface{}) (map[string]inte } // Put in KV. -func (s *vault) Put(mountPath, secretePath string, data map[string]interface{}) error { - _, err := s.cli.KVv2(mountPath).Put(context.Background(), secretePath, data) +func (s *vault) Put(secretePath string, data map[string]interface{}) error { + _, err := s.cli.KVv2(s.kvMountPath).Put(context.Background(), secretePath, data) return err } // Get from KV. -func (s *vault) Get(mountPath, secretePath string) (map[string]interface{}, error) { - sec, err := s.cli.KVv2(mountPath).Get(context.Background(), secretePath) +func (s *vault) Get(secretePath string) (map[string]interface{}, error) { + sec, err := s.cli.KVv2(s.kvMountPath).Get(context.Background(), secretePath) if sec != nil { return sec.Data, err } diff --git a/internal/resource/ca.go b/internal/resource/ca.go new file mode 100644 index 0000000..0040471 --- /dev/null +++ b/internal/resource/ca.go @@ -0,0 +1,102 @@ +package resource + +import ( + "crypto/tls" + "fmt" + "path" + "time" + + "go.uber.org/zap" + + "github.com/fraima/key-keeper/internal/config" +) + +func (s *resource) checkCA(cert config.Certificate) { + var ( + crt, key []byte + err error + ) + + defer func() { + if err := s.storeCertificate(cert.HostPath, crt, key); err != nil { + zap.L().Error( + "stored intermediate-ca", + zap.Error(err), + ) + } + }() + + crt, key, err = s.readCA(cert.VaultPath) + if err == nil { + var ca *tls.Certificate + ca, err = parseToCert(crt, key) + if err != nil { + err = fmt.Errorf("parse : %w", err) + } + if ca != nil && time.Until(ca.Leaf.NotAfter) < cert.RenewBefore { + err = fmt.Errorf("expired until(h) %f", time.Until(ca.Leaf.NotAfter).Hours()) + } + } + + if err != nil { + zap.L().Warn( + "intermediate ca", + zap.String("common_name", cert.Spec.CommonName+"-ca"), + zap.Error(err), + ) + } else { + return + } + + crt, key, err = s.generateCA(cert) + if err != nil { + zap.L().Error( + "generate intermediate-ca", + zap.Error(err), + ) + } + +} + +func (s *resource) generateCA(cert config.Certificate) (crt, key []byte, err error) { + // create intermediate ca with exported key + csrData := map[string]interface{}{ + "common_name": fmt.Sprintf("%s Intermediate Authority", cert.Spec.CommonName), + "ttl": "8760h", + } + + vaultPath := path.Join(cert.VaultPath, "intermediate/generate/exported") + csr, err := s.vault.Write(vaultPath, csrData) + if err != nil { + err = fmt.Errorf("create: %w", err) + return + } + + // send the intermediate ca with exported key's CSR to the root CA for signing + icaData := map[string]interface{}{ + "csr": csr["csr"], + "format": "pem_bundle", + "ttl": "8760h", + } + + vaultPath = path.Join(cert.VaultRootCAPath, "root/sign-intermediate") + ica, err := s.vault.Write(vaultPath, icaData) + if err != nil { + err = fmt.Errorf("send the intermediate ca with exported key's CSR to the root CA for signing CA: %w", err) + return + } + + // publish the signed certificate back to the intermediate ca with exported key + certData := map[string]interface{}{ + "certificate": ica["certificate"], + } + + vaultPath = path.Join(cert.VaultPath, "intermediate/set-signed") + if _, err = s.vault.Write(vaultPath, certData); err != nil { + err = fmt.Errorf("publish the signed certificate back to the intermediate ca with exported key: %w", err) + return + } + + zap.L().Info("intermediate-ca generated", zap.String("common_name", cert.Spec.CommonName)) + return []byte(ica["certificate"].(string)), []byte(csr["private_key"].(string)), nil +} diff --git a/internal/resource/csr.go b/internal/resource/csr.go index 3cd3644..ecbcc8a 100644 --- a/internal/resource/csr.go +++ b/internal/resource/csr.go @@ -10,12 +10,12 @@ import ( "go.uber.org/zap" - "github.com/fraima/key-keeper/internal/controller" + "github.com/fraima/key-keeper/internal/config" ) -func (s *resource) csr(i controller.CSR) { +func (s *resource) checkCSR(i config.Certificate) { csr, err := s.readCertificate(i.HostPath) - if csr != nil && time.Until(csr.Leaf.NotAfter) > s.cfg.Certificates.ReissueInterval { + if csr != nil && time.Until(csr.Leaf.NotAfter) > i.RenewBefore { return } if err != nil && !os.IsNotExist(err) { @@ -26,15 +26,15 @@ func (s *resource) csr(i controller.CSR) { if err != nil { zap.L().Error( "generate csr", - zap.String("common_name", i.CommonName), + zap.String("common_name", i.Spec.CommonName), zap.Error(err), ) } - if err = s.storeCSR(i, cert, key); err != nil { + if err = s.storeCertificate(i.HostPath, cert, key); err != nil { zap.L().Error( "store csr", - zap.String("common_name", i.CommonName), + zap.String("common_name", i.Spec.CommonName), zap.Error(err), ) return @@ -45,21 +45,21 @@ func (s *resource) csr(i controller.CSR) { err := exec.Command(cmd[0], cmd[1:]...).Run() zap.L().Error( "csr trigger", - zap.String("common_name", i.CommonName), + zap.String("common_name", i.Spec.CommonName), zap.String("command", command), zap.Error(err), ) } - zap.L().Info("csr generated", zap.String("common_name", i.CommonName)) + zap.L().Info("csr generated", zap.String("common_name", i.Spec.CommonName)) } -func (s *resource) generateCSR(i controller.CSR) ([]byte, []byte, error) { +func (s *resource) generateCSR(i config.Certificate) ([]byte, []byte, error) { certData := map[string]interface{}{ - "common_name": i.CommonName, - "alt_names": strings.Join(i.Hosts, ","), - "ip_sans": strings.Join(i.IPs, ","), + "common_name": i.Spec.CommonName, + "alt_names": strings.Join(i.Spec.Hostnames, ","), + "ip_sans": strings.Join(i.Spec.IPAddresses, ","), } - path := path.Join(i.CertPath, "issue", i.Role) + path := path.Join(i.VaultPath, "issue", i.VaultRole) cert, err := s.vault.Write(path, certData) if err != nil { return nil, nil, fmt.Errorf("generate with path %s : %w", path, err) @@ -67,10 +67,3 @@ func (s *resource) generateCSR(i controller.CSR) ([]byte, []byte, error) { return []byte(cert["certificate"].(string)), []byte(cert["private_key"].(string)), nil } - -func (s *resource) storeCSR(i controller.CSR, cert, key []byte) error { - if err := s.storeCertificate(i.HostPath, cert, key); err != nil { - return fmt.Errorf("host path %s : %w", i.HostPath, err) - } - return nil -} diff --git a/internal/resource/intermediate-ca-exported-key.go b/internal/resource/intermediate-ca-exported-key.go deleted file mode 100644 index 1074590..0000000 --- a/internal/resource/intermediate-ca-exported-key.go +++ /dev/null @@ -1,126 +0,0 @@ -package resource - -import ( - "crypto/tls" - "fmt" - "path" - "time" - - "go.uber.org/zap" - - "github.com/fraima/key-keeper/internal/controller" -) - -func (s *resource) intermediateCAWithExportedKey(i controller.IntermediateCA) { - var ( - crt, key []byte - err error - ) - - defer func() { - if err := s.storeIntermediateCAWithExportedKey(i, crt, key); err != nil { - zap.L().Error( - "stored intermediate ca with exported key", - zap.Error(err), - ) - } - }() - - crt, key, err = s.readIntermediateCAWithExportedKey(i) - if err != nil { - zap.L().Error( - "read intermediate ca with exported key", - zap.String("common_name", i.CommonName+"-ca"), - zap.Error(err), - ) - } else { - return - } - if i.Generate { - crt, key, err = s.generateIntermediateCAWithExportedKey(i) - if err != nil { - zap.L().Error( - "generate intermediate ca with exported key", - zap.Error(err), - ) - } - } -} - -func (s *resource) readIntermediateCAWithExportedKey(i controller.IntermediateCA) (crt, key []byte, err error) { - storedICA, err := s.vault.Get(s.cfg.Certificates.VaultKV, i.CommonName+"-ca") - if err != nil { - err = fmt.Errorf("get from vault_kv %s : %w", s.cfg.Certificates.VaultKV, err) - return - } - - crt, key = []byte(storedICA["certificate"].(string)), []byte(storedICA["private_key"].(string)) - var ca *tls.Certificate - ca, err = parseToCert(crt, key) - if err != nil { - err = fmt.Errorf("parse : %w", err) - } - if ca != nil && time.Until(ca.Leaf.NotAfter) < s.cfg.Certificates.ReissueInterval { - err = fmt.Errorf("expired until(h) %f", time.Until(ca.Leaf.NotAfter).Hours()) - } - return -} - -func (s *resource) generateIntermediateCAWithExportedKey(i controller.IntermediateCA) (crt, key []byte, err error) { - // create intermediate ca with exported key - csrData := map[string]interface{}{ - "common_name": fmt.Sprintf("%s Intermediate Authority", i.CommonName), - "ttl": "8760h", - } - - path := path.Join(i.CertPath, "intermediate/generate/exported") - csr, err := s.vault.Write(path, csrData) - if err != nil { - err = fmt.Errorf("create: %w", err) - return - } - - // send the intermediate ca with exported key's CSR to the root CA for signing - icaData := map[string]interface{}{ - "csr": csr["csr"], - "format": "pem_bundle", - "ttl": "8760h", - } - - path = i.RootPathCA + "/root/sign-intermediate" - ica, err := s.vault.Write(path, icaData) - if err != nil { - err = fmt.Errorf("send the intermediate ca with exported key's CSR to the root CA for signing CA: %w", err) - return - } - - // publish the signed certificate back to the intermediate ca with exported key - certData := map[string]interface{}{ - "certificate": ica["certificate"], - } - - path = i.CertPath + "/intermediate/set-signed" - if _, err = s.vault.Write(path, certData); err != nil { - err = fmt.Errorf("publish the signed certificate back to the intermediate ca with exported key: %w", err) - return - } - - zap.L().Info("intermediate-ca generated", zap.String("common_name", i.CommonName)) - return []byte(ica["certificate"].(string)), []byte(csr["private_key"].(string)), nil -} - -func (s *resource) storeIntermediateCAWithExportedKey(i controller.IntermediateCA, crt, key []byte) error { - // saving the created intermediate ca with exported key - storedICA := map[string]interface{}{ - "certificate": string(crt), - "private_key": string(key), - } - if err := s.vault.Put(s.cfg.Certificates.VaultKV, i.CommonName+"-ca", storedICA); err != nil { - return fmt.Errorf("saving in vault: %w", err) - } - - if err := s.storeCertificate(i.HostPath, crt, key); err != nil { - return fmt.Errorf("host path %s : %w", i.HostPath, err) - } - return nil -} diff --git a/internal/resource/intermediate-ca.go b/internal/resource/intermediate-ca.go deleted file mode 100644 index 5bb1ef4..0000000 --- a/internal/resource/intermediate-ca.go +++ /dev/null @@ -1,106 +0,0 @@ -package resource - -import ( - "fmt" - "path" - - "go.uber.org/zap" - - "github.com/fraima/key-keeper/internal/controller" -) - -func (s *resource) intermediateCA(i controller.IntermediateCA) { - var ( - crt []byte - err error - ) - - defer func() { - if err := s.storeIntermediateCA(i, crt, nil); err != nil { - zap.L().Error( - "stored intermediate-ca", - zap.Error(err), - ) - } - }() - - crt, err = s.readIntermediateCA(i) - if err != nil { - zap.L().Error( - "read intermediate ca", - zap.String("common_name", i.CommonName+"-ca"), - zap.Error(err), - ) - } else { - return - } - - if i.Generate { - crt, err = s.generateIntermediateCA(i) - if err != nil { - zap.L().Error( - "generate intermediate-ca", - zap.Error(err), - ) - } - } -} - -func (s *resource) readIntermediateCA(i controller.IntermediateCA) (crt []byte, err error) { - path := path.Join(i.CertPath, "cert/ca_chain") - ica, err := s.vault.Read(path) - if ica != nil { - return []byte(ica["certificate"].(string)), err - } - return -} - -func (s *resource) generateIntermediateCA(i controller.IntermediateCA) (crt []byte, err error) { - // create intermediate CA - csrData := map[string]interface{}{ - "common_name": fmt.Sprintf("%s Intermediate Authority", i.CommonName), - "ttl": "8760h", - } - - path := path.Join(i.CertPath, "intermediate/generate/internal") - csr, err := s.vault.Write(path, csrData) - if err != nil { - err = fmt.Errorf("create intermediate CA: %w", err) - return - } - - // send the intermediate CA's CSR to the root CA for signing - icaData := map[string]interface{}{ - "csr": csr["csr"], - "format": "pem_bundle", - "ttl": "8760h", - } - - path = i.RootPathCA + "/root/sign-intermediate" - ica, err := s.vault.Write(path, icaData) - if err != nil { - err = fmt.Errorf("send the intermediate CA's CSR to the root CA for signing CA: %w", err) - return - } - - // publish the signed certificate back to the Intermediate CA - certData := map[string]interface{}{ - "certificate": ica["certificate"], - } - - path = i.CertPath + "/intermediate/set-signed" - if _, err = s.vault.Write(path, certData); err != nil { - err = fmt.Errorf("publish the signed certificate back to the Intermediate CA: %w", err) - return - } - - zap.L().Info("intermediate-ca generated", zap.String("common_name", i.CommonName)) - return []byte(ica["certificate"].(string)), nil -} - -func (s *resource) storeIntermediateCA(i controller.IntermediateCA, crt, key []byte) error { - if err := s.storeCertificate(i.HostPath, crt, key); err != nil { - return fmt.Errorf("host path %s : %w", i.HostPath, err) - } - return nil -} diff --git a/internal/resource/rsa.go b/internal/resource/key.go similarity index 54% rename from internal/resource/rsa.go rename to internal/resource/key.go index dd08bc1..95c4f49 100644 --- a/internal/resource/rsa.go +++ b/internal/resource/key.go @@ -6,13 +6,14 @@ import ( "crypto/x509" "encoding/pem" "fmt" + "strings" "go.uber.org/zap" - "github.com/fraima/key-keeper/internal/controller" + "github.com/fraima/key-keeper/internal/config" ) -func (s *resource) rsa(i controller.RSA) { +func (s *resource) checkKey(i config.Key) { private, public, err := s.readRSA(i) if err != nil { zap.L().Warn( @@ -20,7 +21,7 @@ func (s *resource) rsa(i controller.RSA) { zap.String("name", i.Name), zap.Error(err), ) - private, public, err = s.GenerateRSA() + private, public, err = s.generateKey(i.PrivateKey) if err != nil { zap.L().Error( "generate rsa", @@ -30,20 +31,24 @@ func (s *resource) rsa(i controller.RSA) { return } zap.L().Debug("rsa is created", zap.String("name", i.Name)) - storedRSA := map[string]interface{}{ - "private": string(private), - "public": string(public), - } - if err := s.vault.Put(s.cfg.Keys.VaultKV, i.Name, storedRSA); err != nil { - zap.L().Error( - "store rsa in kv", - zap.String("name", i.Name), - zap.String("kv", s.cfg.Keys.VaultKV), - zap.Error(err), - ) - return + if i.Public { + storedRSA := map[string]interface{}{ + "private": string(private), + "public": string(public), + } + + if err := s.vault.Put(i.Name, storedRSA); err != nil { + zap.L().Error( + "store rsa in kv", + zap.String("name", i.Name), + zap.Error(err), + ) + return + } + zap.L().Debug("rsa is saved in kv", zap.String("name", i.Name)) } + } else { zap.L().Debug("rsa is read", zap.String("name", i.Name)) } @@ -60,10 +65,10 @@ func (s *resource) rsa(i controller.RSA) { zap.L().Debug("rsa is stored", zap.String("name", i.Name)) } -func (s *resource) readRSA(i controller.RSA) (private []byte, public []byte, err error) { - storedRSA, err := s.vault.Get(s.cfg.Keys.VaultKV, i.Name) +func (s *resource) readRSA(i config.Key) (private []byte, public []byte, err error) { + storedRSA, err := s.vault.Get(i.Name) if err != nil { - err = fmt.Errorf("get from vault_kv %s : %w", s.cfg.Keys.VaultKV, err) + err = fmt.Errorf("get from vault_kv : %w", err) return } @@ -71,8 +76,16 @@ func (s *resource) readRSA(i controller.RSA) (private []byte, public []byte, err return } -func (s *resource) GenerateRSA() (private []byte, public []byte, err error) { - privKey, err := rsa.GenerateKey(rand.Reader, 4096) +func (s *resource) generateKey(info config.PrivateKey) (private []byte, public []byte, err error) { + if strings.ToLower(info.Algorithm) != "rsa" { + err = fmt.Errorf("the algorithm %s is not supported", info.Algorithm) + return + } + return s.generateRSA(info.Size) +} + +func (s *resource) generateRSA(size int) (private []byte, public []byte, err error) { + privKey, err := rsa.GenerateKey(rand.Reader, size) if err != nil { return } diff --git a/internal/resource/resource.go b/internal/resource/resource.go index 0381678..1daf56e 100644 --- a/internal/resource/resource.go +++ b/internal/resource/resource.go @@ -3,66 +3,62 @@ package resource import ( "sync" - "go.uber.org/zap" - + "github.com/fraima/key-keeper/internal/config" "github.com/fraima/key-keeper/internal/controller" + "go.uber.org/zap" ) type resource struct { - vault controller.Vault - cfg controller.RecourceConfig + vault controller.Vault + certificate map[string]config.Certificate + key map[string]config.Key } func Preparing( vault controller.Vault, - cfg controller.RecourceConfig, ) controller.Resource { - r := &resource{ - vault: vault, - cfg: cfg, + return &resource{ + vault: vault, + certificate: make(map[string]config.Certificate), + key: make(map[string]config.Key), } - r.Check() - return r } func (s *resource) Check() { wg := &sync.WaitGroup{} - zap.L().Debug("certificate-root-ca") - for _, c := range s.cfg.Certificates.RootCA { + zap.L().Debug("certificate-intermediate-ca") + for _, cert := range s.certificate { wg.Add(1) - go func(c controller.RootCA) { + go func(c config.Certificate) { defer wg.Done() - s.rootCA(c) - }(c) + if c.IsCA { + if c.IsCA { + s.checkCA(c) + } else { + s.checkCSR(c) + } + } + }(cert) } wg.Wait() - zap.L().Debug("certificate-intermediate-ca") - for _, c := range s.cfg.Certificates.IntermediateCA { + zap.L().Debug("keys") + for _, key := range s.key { wg.Add(1) - go func(c controller.IntermediateCA) { - defer wg.Done() - if c.ExportedKey { - s.intermediateCAWithExportedKey(c) - } else { - s.intermediateCA(c) - } - }(c) + go func(k config.Key) { + s.checkKey(k) + }(key) } wg.Wait() +} - zap.L().Debug("certificate-csr") - for _, c := range s.cfg.Certificates.CSR { - go func(c controller.CSR) { - s.csr(c) - }(c) +func (s *resource) Add(r config.Resources) { + for _, cert := range r.Certificates { + s.certificate[cert.Name] = cert } - - zap.L().Debug("key-rsa") - for _, k := range s.cfg.Keys.RSA { - go func(k controller.RSA) { - s.rsa(k) - }(k) + for _, key := range r.Keys { + s.key[key.Name] = key } + s.Check() } diff --git a/internal/resource/root-ca.go b/internal/resource/root-ca.go deleted file mode 100644 index 4b3f6d7..0000000 --- a/internal/resource/root-ca.go +++ /dev/null @@ -1,56 +0,0 @@ -package resource - -import ( - "fmt" - "path" - - "go.uber.org/zap" - - "github.com/fraima/key-keeper/internal/controller" -) - -func (s *resource) rootCA(i controller.RootCA) { - isExist, err := s.isExistRootCA(i) - if err != nil { - zap.L().Warn( - "existing root-ca", - zap.String("common_name", i.CommonName), - zap.Error(err), - ) - } - if isExist { - return - } - - if err := s.generateRootCA(i); err != nil { - zap.L().Error( - "generate root-ca", - zap.String("common_name", i.CommonName), - zap.Error(err), - ) - return - } - zap.L().Info("root-ca generated", zap.String("common_name", i.CommonName)) -} - -func (s *resource) isExistRootCA(i controller.RootCA) (bool, error) { - path := path.Join(i.RootPathCA, "cert/ca") - rootCA, err := s.vault.Read(path) - if err != nil { - err = fmt.Errorf("read root CA: %w", err) - } - return rootCA != nil, err -} - -func (s *resource) generateRootCA(i controller.RootCA) error { - rootCAData := map[string]interface{}{ - "common_name": i.CommonName, - "ttl": "8760h", - } - path := path.Join(i.RootPathCA, "root/generate/internal") - _, err := s.vault.Write(path, rootCAData) - if err != nil { - err = fmt.Errorf("create root CA: %w", err) - } - return err -} diff --git a/internal/resource/store.go b/internal/resource/store.go index 606e11a..9ffb9aa 100644 --- a/internal/resource/store.go +++ b/internal/resource/store.go @@ -5,6 +5,7 @@ import ( "crypto/x509" "fmt" "os" + "path" ) func (s *resource) storeKey(path string, privare, public []byte) error { @@ -44,9 +45,32 @@ func (s *resource) readCertificate(path string) (*tls.Certificate, error) { return nil, err } return parseToCert(crt, key) +} +func (s *resource) readCA(vaulPath string) (crt, key []byte, err error) { + vaulPath = path.Join(vaulPath, "cert/ca_chain") + ica, err := s.vault.Read(vaulPath) + if ica != nil { + if c, ok := ica["certificate"]; ok { + crt = []byte(c.(string)) + } + if k, ok := ica["private_key"]; ok { + key = []byte(k.(string)) + } + } + return } +// func (s *resource) readCA(cert config.Certificate) (crt, key []byte, err error) { +// storedICA, err := s.vault.Get(cert.Spec.CommonName + "-ca") +// if err != nil { +// err = fmt.Errorf("get from vault_kv : %w", err) +// return +// } + + +// } + func parseToCert(crt, key []byte) (*tls.Certificate, error) { cert, err := tls.X509KeyPair(crt, key) if err != nil { From 3d1223c39b75bee59ff224b60508b5f1baec5325 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 30 Aug 2022 11:17:03 +0300 Subject: [PATCH 102/220] update --- config-struct.yaml | 12 ++++++--- internal/config/types.go | 30 ++++++++++++++-------- internal/resource/ca.go | 52 ++++++++++++++++++++++++-------------- internal/resource/csr.go | 2 +- internal/resource/store.go | 10 -------- 5 files changed, 62 insertions(+), 44 deletions(-) diff --git a/config-struct.yaml b/config-struct.yaml index db5292b..ca4c005 100644 --- a/config-struct.yaml +++ b/config-struct.yaml @@ -20,6 +20,9 @@ certificates: # Описывает список доступных certificates issuerRef: # IssuerRef references a properly configured ACME-type Issuer which should be used to create this Order. If the Issuer does not exist, processing will be retried. If the Issuer is not an 'ACME' Issuer, an error will be returned and the Order will be marked as failed. name: string # Имя вызываемого ISSUER isCa: bool # IsCA will request to mark the certificate as valid for certificate signing when submitting to the issuer. This will automatically add the `cert sign` usage to the list of `usages`. + ca: # Альтернатива блоку certificates.intermediate_ca + exportedKey: bool # запрашивать приватный ключ или нет + generate: bool # генерить ЦА или запросить существующий CA spec: # блок описывающий certificate commonName: string # CommonName is the common name as specified on the DER encoded CSR. If specified, this value must also be present in `dnsNames` or `ipAddresses`. This field must match the corresponding field on the DER encoded CSR. subject: # блок описывающий принадлежность certificate @@ -39,12 +42,13 @@ certificates: # Описывает список доступных certificates hostnames: list of string # List of DNSNames that this solver will be used to solve. If specified and a match is found, a dnsNames selector will take precedence over a dnsZones selector. If multiple solvers match with the same dnsNames value, the solver with the most matching labels in matchLabels will be selected. If neither has more matches, the solver defined earlier in the list will be selected. ipAddresses: list of string # IPAddresses is a list of IP addresses that should be included as part of the Order validation process. This field must match the corresponding field on the DER encoded CSR. ttl: string # на какой промежуток времени заказывается сертификат + vault: + role: string # альтернатива блоку csr[*].role + path: string # Путь к сейфу Inermediate CA где будет заказан сертификат + rootCAPath: string # Путь к root CA hostPath: string # путь, где будет размещен секрет по маске ${hostPathCert}/${certName} - vaultPath: string # Путь к сейфу Inermediate CA где будет заказан сертификат - vaultRole: string - vaultRootCAPath: string # Путь к сейфу корневого CA - trigger: list of string # список bash команд которые применятся после обновления сертификата renewBefore: string # за сколько до истечения надо перевыпустить + trigger: list of string # список bash команд которые применятся после обновления сертификата keys: # Описывает список доступных keys - name: # Имя key diff --git a/internal/config/types.go b/internal/config/types.go index eb30d4b..24ab2a4 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -18,16 +18,15 @@ type Resources struct { } type Certificate struct { - Name string `yaml:"name"` - IssuerRef IssuerRef `yaml:"issuerRef"` - IsCA bool `yaml:"isCa"` - Spec Spec `yaml:"spec"` - HostPath string `yaml:"hostPath"` - VaultPath string `yaml:"vaultPath"` - VaultRole string `yaml:"vaultRole"` - VaultRootCAPath string `yaml:"vaulRrootCAPath"` - Trigger []string `yaml:"trigger"` - RenewBefore time.Duration `yaml:"renewBefore" ` + Name string `yaml:"name"` + IssuerRef IssuerRef `yaml:"issuerRef"` + IsCA bool `yaml:"isCa"` + CA CA `yaml:"ca"` + Spec Spec `yaml:"spec"` + Vault CertVault `yaml:"vault"` + HostPath string `yaml:"hostPath"` + RenewBefore time.Duration `yaml:"renewBefore"` + Trigger []string `yaml:"trigger"` } type Key struct { @@ -42,6 +41,11 @@ type IssuerRef struct { Name string `yaml:"name"` } +type CA struct { + ExportedKey bool `yaml:"exportedKey"` + Generate bool `yaml:"generate"` +} + type Vault struct { Server string `yaml:"address"` Auth Auth `yaml:"auth"` @@ -81,6 +85,12 @@ type Spec struct { TTL string `yaml:"ttl"` } +type CertVault struct { + Role string `yaml:"role"` + Path string `yaml:"path"` + RootCAPath string `yaml:"rootCAPath"` +} + type Subject struct { Countries []string `yaml:"countries"` Localities []string `yaml:"localities"` diff --git a/internal/resource/ca.go b/internal/resource/ca.go index 0040471..bfef96c 100644 --- a/internal/resource/ca.go +++ b/internal/resource/ca.go @@ -26,7 +26,7 @@ func (s *resource) checkCA(cert config.Certificate) { } }() - crt, key, err = s.readCA(cert.VaultPath) + crt, key, err = s.readCA(cert.Vault.Path) if err == nil { var ca *tls.Certificate ca, err = parseToCert(crt, key) @@ -48,55 +48,69 @@ func (s *resource) checkCA(cert config.Certificate) { return } - crt, key, err = s.generateCA(cert) - if err != nil { - zap.L().Error( - "generate intermediate-ca", - zap.Error(err), - ) + if cert.CA.Generate { + crt, key, err = s.generateCA(cert) + if err != nil { + zap.L().Error( + "generate intermediate-ca", + zap.Error(err), + ) + return + } } - } func (s *resource) generateCA(cert config.Certificate) (crt, key []byte, err error) { - // create intermediate ca with exported key + // create intermediate ca csrData := map[string]interface{}{ "common_name": fmt.Sprintf("%s Intermediate Authority", cert.Spec.CommonName), - "ttl": "8760h", + "ttl": cert.Spec.TTL, + } + + keyType := "internal" + if cert.CA.ExportedKey { + keyType = "exported" } - vaultPath := path.Join(cert.VaultPath, "intermediate/generate/exported") + vaultPath := path.Join(cert.Vault.Path, "intermediate/generate", keyType) csr, err := s.vault.Write(vaultPath, csrData) if err != nil { err = fmt.Errorf("create: %w", err) return } - // send the intermediate ca with exported key's CSR to the root CA for signing + // send the intermediate ca 's CSR to the root CA for signing icaData := map[string]interface{}{ "csr": csr["csr"], "format": "pem_bundle", - "ttl": "8760h", + "ttl": cert.Spec.TTL, } - vaultPath = path.Join(cert.VaultRootCAPath, "root/sign-intermediate") + vaultPath = path.Join(cert.Vault.RootCAPath, "root/sign-intermediate") ica, err := s.vault.Write(vaultPath, icaData) if err != nil { - err = fmt.Errorf("send the intermediate ca with exported key's CSR to the root CA for signing CA: %w", err) + err = fmt.Errorf("send the intermediate ca CSR to the root CA for signing CA: %w", err) return } - // publish the signed certificate back to the intermediate ca with exported key + // publish the signed certificate back to the intermediate ca certData := map[string]interface{}{ "certificate": ica["certificate"], } - vaultPath = path.Join(cert.VaultPath, "intermediate/set-signed") + vaultPath = path.Join(cert.Vault.Path, "intermediate/set-signed") if _, err = s.vault.Write(vaultPath, certData); err != nil { - err = fmt.Errorf("publish the signed certificate back to the intermediate ca with exported key: %w", err) + err = fmt.Errorf("publish the signed certificate back to the intermediate ca : %w", err) return } + if c, ok := ica["certificate"]; ok { + crt = []byte(c.(string)) + } + if k, ok := csr["private_key"]; ok { + key = []byte(k.(string)) + } + zap.L().Info("intermediate-ca generated", zap.String("common_name", cert.Spec.CommonName)) - return []byte(ica["certificate"].(string)), []byte(csr["private_key"].(string)), nil + return } diff --git a/internal/resource/csr.go b/internal/resource/csr.go index ecbcc8a..7a878e3 100644 --- a/internal/resource/csr.go +++ b/internal/resource/csr.go @@ -59,7 +59,7 @@ func (s *resource) generateCSR(i config.Certificate) ([]byte, []byte, error) { "alt_names": strings.Join(i.Spec.Hostnames, ","), "ip_sans": strings.Join(i.Spec.IPAddresses, ","), } - path := path.Join(i.VaultPath, "issue", i.VaultRole) + path := path.Join(i.Vault.Path, "issue", i.Vault.Role) cert, err := s.vault.Write(path, certData) if err != nil { return nil, nil, fmt.Errorf("generate with path %s : %w", path, err) diff --git a/internal/resource/store.go b/internal/resource/store.go index 9ffb9aa..d000721 100644 --- a/internal/resource/store.go +++ b/internal/resource/store.go @@ -61,16 +61,6 @@ func (s *resource) readCA(vaulPath string) (crt, key []byte, err error) { return } -// func (s *resource) readCA(cert config.Certificate) (crt, key []byte, err error) { -// storedICA, err := s.vault.Get(cert.Spec.CommonName + "-ca") -// if err != nil { -// err = fmt.Errorf("get from vault_kv : %w", err) -// return -// } - - -// } - func parseToCert(crt, key []byte) (*tls.Certificate, error) { cert, err := tls.X509KeyPair(crt, key) if err != nil { From 89bedb4185e7c68a69131980b21d0e0640106997 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 30 Aug 2022 11:17:08 +0300 Subject: [PATCH 103/220] update --- internal/resource/ca.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/internal/resource/ca.go b/internal/resource/ca.go index bfef96c..ded36b6 100644 --- a/internal/resource/ca.go +++ b/internal/resource/ca.go @@ -53,9 +53,15 @@ func (s *resource) checkCA(cert config.Certificate) { if err != nil { zap.L().Error( "generate intermediate-ca", + zap.String("common_name", cert.Spec.CommonName), zap.Error(err), ) return + } else { + zap.L().Info( + "intermediate-ca generated", + zap.String("common_name", cert.Spec.CommonName), + ) } } } @@ -111,6 +117,5 @@ func (s *resource) generateCA(cert config.Certificate) (crt, key []byte, err err key = []byte(k.(string)) } - zap.L().Info("intermediate-ca generated", zap.String("common_name", cert.Spec.CommonName)) return } From dfe9eff16a2f37ef2379f1ddb1c21fadd1867a28 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 30 Aug 2022 14:01:18 +0300 Subject: [PATCH 104/220] up --- README.md | 7 ++++++- cmd/key-keeper/main.go | 9 ++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index ecdee8c..3e5633d 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,14 @@ go build -o key-keeper cmd/key-keeper/main.go # Run bim ```bash -key-keeper -config /path/to/config +key-keeper -config-dir /path/to/config-dir -config-regexp .*.conf ``` +> config-dir - путь до каталога с конфигами +> +> config-regexp - регуляроное выражения для имени файлов которые содержат конфиги для key-keeper + + Example config.yml ```yaml diff --git a/cmd/key-keeper/main.go b/cmd/key-keeper/main.go index ad0220d..39e7483 100644 --- a/cmd/key-keeper/main.go +++ b/cmd/key-keeper/main.go @@ -10,8 +10,8 @@ import ( "github.com/fraima/key-keeper/internal/config" "github.com/fraima/key-keeper/internal/controller" - "github.com/fraima/key-keeper/internal/resource" "github.com/fraima/key-keeper/internal/issuer/vault" + "github.com/fraima/key-keeper/internal/resource" ) var ( @@ -27,16 +27,11 @@ func main() { } zap.ReplaceGlobals(logger) - var globalConfig, configDir, configNameLayout string - flag.StringVar(&globalConfig, "config-global", "", "path to global config") + var configDir, configNameLayout string flag.StringVar(&configDir, "config-dir", "", "path to dir with configs") flag.StringVar(&configNameLayout, "config-regexp", "", "regexp for config files names") flag.Parse() - if globalConfig == "" { - zap.L().Fatal("not found global config param") - } - if configDir == "" { zap.L().Fatal("not found config path param") } From 4176beed04f69f1f56ddb0607236ebf3e43037f9 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 30 Aug 2022 16:54:25 +0300 Subject: [PATCH 105/220] update --- cmd/key-keeper/main.go | 1 + config-struct-fraima.yaml | 79 ------ example.struct.yaml | 78 ------ example.yaml | 410 ++---------------------------- internal/config/config.go | 6 +- internal/config/types.go | 2 +- internal/controller/controller.go | 6 +- test.example.yaml | 120 --------- 8 files changed, 36 insertions(+), 666 deletions(-) delete mode 100644 config-struct-fraima.yaml delete mode 100644 example.struct.yaml delete mode 100644 test.example.yaml diff --git a/cmd/key-keeper/main.go b/cmd/key-keeper/main.go index 39e7483..08a5e07 100644 --- a/cmd/key-keeper/main.go +++ b/cmd/key-keeper/main.go @@ -52,6 +52,7 @@ func main() { vault.Connect, resource.Preparing, ) + go cntl.RefreshResource() go cntl.Start() zap.L().Info("started") diff --git a/config-struct-fraima.yaml b/config-struct-fraima.yaml deleted file mode 100644 index efd4c47..0000000 --- a/config-struct-fraima.yaml +++ /dev/null @@ -1,79 +0,0 @@ ---- -global: # блок описывает базовую конфигурацию key-keeper - vault: # блок описывает базовый конфиг Vault - serever: string # rename $address (адрес волта) - caBundle: string # new (сертификат для подключения к волту - при http не должен фигурировать) - tlsInsecure: bool # new при указании тру скипать ssl верификацию - auth: # блок авторизации в Vault - bootstrap: # блок авторизации в Vault по бутстрап токену - tokenPath: string # rename $bootstrap_token - appRole: # блок авторизации в Vault по аппроли - name: string # rename $approle_name - path: string # rename $approle_path - roleIdPath: string # rename $local_path_to_role_id - secretIdPath: string # rename $local_path_to_secret_id - kv: # блок описывает базовый KV - path: string # блок описывает базовый путь KV - -issuers: # Описывает список доступных issuers - - name: string # Имя issuer - vault: # Все переменные global.Vault.* могут быть переопределены тут в блоке vault - role: # Блок описывающий роль волта - name: string # альтернатива блоку csr[*].role - path: string # альтернатива блоку csr[*].cert_path - intermediate: # Альтернатива блоку certificates.intermediate_ca - rootPath: string # Путь к root CA - exportedKey: bool # запрашивать приватный ключ или нет - generate: bool # генерить ЦА или запросить существующий CA - server: string # rename $address (адрес волта) - caBundle: string # new (сертификат для подключения к волту - при http не должен фигурировать) - tlsInsecure: bool # new при указании тру скипать ssl верификацию - auth: # блок авторизации в Vault - bootstrap: # блок авторизации в Vault по бутстрап токену - tokenPath: string # rename $bootstrap_token - appRole: # блок авторизации в Vault по аппроли - name: string # rename $approle_name - path: string # rename $approle_path - roleIdPath: string # rename $local_path_to_role_id - secretIdPath: string # rename $local_path_to_secret_id - -certificates: # Описывает список доступных certificates - - name: string # Имя certificate - issuerRef: # IssuerRef references a properly configured ACME-type Issuer which should be used to create this Order. If the Issuer does not exist, processing will be retried. If the Issuer is not an 'ACME' Issuer, an error will be returned and the Order will be marked as failed. - name: string # Имя вызываемого ISSUER - spec: # блок описывающий certificate - duration: string # на какой промежуток времени заказывается сертификат - renewBefore: string # за сколько до истечения надо перевыпустить - subject: # блок описывающий принадлежность certificate - countries: # Countries to be used on the Certificate. - localities: # Cities to be used on the Certificate. - organizationalUnits: # Organizational Units to be used on the Certificate. - organizations: # Organizations to be used on the Certificate. - postalCodes: # Postal codes to be used on the Certificate. - provinces: # State/Provinces to be used on the Certificate. - serialNumber: # Serial number to be used on the Certificate - streetAddresses: # Street addresses to be used on the Certificate. - commonName: string # CommonName is the common name as specified on the DER encoded CSR. If specified, this value must also be present in `dnsNames` or `ipAddresses`. This field must match the corresponding field on the DER encoded CSR. - privateKey: # Options to control private keys used for the Certificate. - algorithm: string # Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either `RSA`,`Ed25519` or `ECDSA` If `algorithm` is specified and `size` is not provided, key size of 256 will be used for `ECDSA` key algorithm and key size of 2048 will be used for `RSA` key algorithm. key size is ignored when using the `Ed25519` key algorithm. - encoding: string # The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 and PKCS#8, respectively. Defaults to `PKCS1` if not specified. - size: intager # Size is the key bit size of the corresponding private key for this certificate. If `algorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified. If `algorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, and will default to `256` if not specified. If `algorithm` is set to `Ed25519`, Size is ignored. No other values are allowed. - usages: list of strings # Usages is the set of x509 usages that are requested for the certificate. Defaults to `digital signature` and `key encipherment` if not specified. - dnsNames: list of strings # List of DNSNames that this solver will be used to solve. If specified and a match is found, a dnsNames selector will take precedence over a dnsZones selector. If multiple solvers match with the same dnsNames value, the solver with the most matching labels in matchLabels will be selected. If neither has more matches, the solver defined earlier in the list will be selected. - ipAddresses: list of strings # IPAddresses is a list of IP addresses that should be included as part of the Order validation process. This field must match the corresponding field on the DER encoded CSR. - isCa: bool # IsCA will request to mark the certificate as valid for certificate signing when submitting to the issuer. This will automatically add the `cert sign` usage to the list of `usages`. - hostPath: string # путь, где будет размещен секрет по маске ${hostPath}/${certName} - trigger: list of strings # список bash команд которые применятся после обновления сертификата - - -keys: # Описывает список доступных keys - - name: # Имя key - host_path: string # путь, где будет размещен секрет по маске ${hostPathCert}/${keyName} - privateKey: # Options to control private keys used for the Certificate. - algorithm: string # Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either `RSA`,`Ed25519` or `ECDSA` If `algorithm` is specified and `size` is not provided, key size of 256 will be used for `ECDSA` key algorithm and key size of 2048 will be used for `RSA` key algorithm. key size is ignored when using the `Ed25519` key algorithm. - encoding: string # The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 and PKCS#8, respectively. Defaults to `PKCS1` if not specified. - size: intager # Size is the key bit size of the corresponding private key for this certificate. If `algorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified. If `algorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, and will default to `256` if not specified. If `algorithm` is set to `Ed25519`, Size is ignored. No other values are allowed. - public: true # если false генерил локально, true генерил локально и пушил в vault - vault: # блок описывает базовый конфиг Vault - kv: # блок описывает базовый KV - path: string # блок описывает базовый путь KV diff --git a/example.struct.yaml b/example.struct.yaml deleted file mode 100644 index f4f7ed8..0000000 --- a/example.struct.yaml +++ /dev/null @@ -1,78 +0,0 @@ ---- -global: # блок описывает базовую конфигурацию key-keeper - vault: # блок описывает базовый конфиг Vault - serever: string # rename $address (адрес волта) - caBundle: string # new (сертификат для подключения к волту - при http не должен фигурировать) - tlsInsecure: bool # new при указании тру скипать ssl верификацию - auth: # блок авторизации в Vault - bootstrap: # блок авторизации в Vault по бутстрап токену - tokenPath: string # rename $bootstrap_token - appRole: # блок авторизации в Vault по аппроли - name: string # rename $approle_name - path: string # rename $approle_path - roleIdPath: string # rename $local_path_to_role_id - secretIdPath: string # rename $local_path_to_secret_id - kv: # блок описывает базовый KV - path: string # блок описывает базовый путь KV - -issuers: # Описывает список доступных issuers - - name: string # Имя issuer - vault: # Все переменные global.Vault.* могут быть переопределены тут в блоке vault - role: # Блок описывающий роль волта - name: string # альтернатива блоку csr[*].role - path: string # альтернатива блоку csr[*].cert_path - intermediate: # Альтернатива блоку certificates.intermediate_ca - rootPath: string # Путь к root CA - exportedKey: bool # запрашивать приватный ключ или нет - generate: bool # генерить ЦА или запросить существующий CA - serever: string # rename $address (адрес волта) - caBundle: string # new (сертификат для подключения к волту - при http не должен фигурировать) - tlsInsecure: bool # new при указании тру скипать ssl верификацию - auth: # блок авторизации в Vault - bootstrap: # блок авторизации в Vault по бутстрап токену - tokenPath: string # rename $bootstrap_token - appRole: # блок авторизации в Vault по аппроли - name: string # rename $approle_name - path: string # rename $approle_path - roleIdPath: string # rename $local_path_to_role_id - secretIdPath: string # rename $local_path_to_secret_id - -certificates: # Описывает список доступных certificates - - name: string # Имя certificate - spec: # блок описывающий certificate - duration: string # на какой промежуток времени заказывается сертификат - renewBefore: string # за сколько до истечения надо перевыпустить - subject: # блок описывающий принадлежность certificate - countries: list of strings # Countries to be used on the Certificate. - localities: list of strings # Cities to be used on the Certificate. - organizationalUnits: list of strings # Organizational Units to be used on the Certificate. - organizations: list of strings # Organizations to be used on the Certificate. - postalCodes: list of strings # Postal codes to be used on the Certificate. - provinces: list of strings # State/Provinces to be used on the Certificate. - serialNumber: list of strings # Serial number to be used on the Certificate - streetAddresses: list of strings # Street addresses to be used on the Certificate. - commonName: string # CommonName is the common name as specified on the DER encoded CSR. If specified, this value must also be present in `dnsNames` or `ipAddresses`. This field must match the corresponding field on the DER encoded CSR. - privateKey: # Options to control private keys used for the Certificate. - algorithm: string # Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either `RSA`,`Ed25519` or `ECDSA` If `algorithm` is specified and `size` is not provided, key size of 256 will be used for `ECDSA` key algorithm and key size of 2048 will be used for `RSA` key algorithm. key size is ignored when using the `Ed25519` key algorithm. - encoding: string # The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 and PKCS#8, respectively. Defaults to `PKCS1` if not specified. - size: intager # Size is the key bit size of the corresponding private key for this certificate. If `algorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified. If `algorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, and will default to `256` if not specified. If `algorithm` is set to `Ed25519`, Size is ignored. No other values are allowed. - usages: list of strings # Usages is the set of x509 usages that are requested for the certificate. Defaults to `digital signature` and `key encipherment` if not specified. - dnsNames: list of strings # List of DNSNames that this solver will be used to solve. If specified and a match is found, a dnsNames selector will take precedence over a dnsZones selector. If multiple solvers match with the same dnsNames value, the solver with the most matching labels in matchLabels will be selected. If neither has more matches, the solver defined earlier in the list will be selected. - ipAddresses: list of strings # IPAddresses is a list of IP addresses that should be included as part of the Order validation process. This field must match the corresponding field on the DER encoded CSR. - issuerRef: # IssuerRef references a properly configured ACME-type Issuer which should be used to create this Order. If the Issuer does not exist, processing will be retried. If the Issuer is not an 'ACME' Issuer, an error will be returned and the Order will be marked as failed. - name: string # Имя вызываемого ISSUER - isCa: bool # IsCA will request to mark the certificate as valid for certificate signing when submitting to the issuer. This will automatically add the `cert sign` usage to the list of `usages`. - hostPathCert: string # путь, где будет размещен секрет по маске ${hostPathCert}/${certName} - trigger: list of strings # список bash команд которые применятся после обновления сертификата - -keys: # Описывает список доступных keys - - name: # Имя key - host_path: string # путь, где будет размещен секрет по маске ${hostPathCert}/${keyName} - privateKey: # Options to control private keys used for the Certificate. - algorithm: string # Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either `RSA`,`Ed25519` or `ECDSA` If `algorithm` is specified and `size` is not provided, key size of 256 will be used for `ECDSA` key algorithm and key size of 2048 will be used for `RSA` key algorithm. key size is ignored when using the `Ed25519` key algorithm. - encoding: string # The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 and PKCS#8, respectively. Defaults to `PKCS1` if not specified. - size: intager # Size is the key bit size of the corresponding private key for this certificate. If `algorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified. If `algorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, and will default to `256` if not specified. If `algorithm` is set to `Ed25519`, Size is ignored. No other values are allowed. - public: true # если false генерил локально, true генерил локально и пушил в vault - vault: # блок описывает базовый конфиг Vault - kv: # блок описывает базовый KV - path: string # блок описывает базовый путь KV diff --git a/example.yaml b/example.yaml index de05703..afaee03 100644 --- a/example.yaml +++ b/example.yaml @@ -1,391 +1,33 @@ --- -global: - vault: - serever: "http://51.250.67.8:9200" - caBundle: "" - tlsInsecure: true - auth: - bootstrap: - tokenPath: "$TOKEN" - appRole: - name: test-role - path: clusters/cluster-1/approle - roleIdPath: "$PATH" - secretIdPath: "$PATH" - kv: - path: "clusters/cluster-1/kv" - issuers: - name: front-proxy-ca vault: - role: - name: "root" - path: "clusters/cluster-1/pki/front-proxy" - intermediate: - rootPath: "clusters/cluster-1/pki/root" - exportedKey: false - generate: false - - - name: front-proxy-client - vault: - role: - name: "front-proxy-client" - path: "clusters/cluster-1/pki/front-proxy" - - - name: kube-ca - vault: - role: - name: "root" - path: "clusters/cluster-1/pki/kubernetes" - intermediate: - rootPath: "clusters/cluster-1/pki/root" - exportedKey: false - generate: false - - - name: kube-apiserver - vault: - role: - name: "kube-apiserver" - path: "clusters/cluster-1/pki/kubernetes" - - - name: kube-apiserver-kubelet-client - vault: - role: - name: "kube-apiserver-kubelet-client" - path: "clusters/cluster-1/pki/kubernetes" - - - name: kube-controller-manager-client - vault: - role: - name: "kube-controller-manager-client" - path: "clusters/cluster-1/pki/kubernetes" - - - name: kube-controller-manager-server - vault: - role: - name: "kube-controller-manager-server" - path: "clusters/cluster-1/pki/kubernetes" - - - name: kube-scheduler-client - vault: - role: - name: "kube-scheduler-client" - path: "clusters/cluster-1/pki/kubernetes" - - - name: kubelet-client - vault: - role: - name: "kubelet-client" - path: "clusters/cluster-1/pki/kubernetes" - - - name: etcd-ca - vault: - role: - name: "root" - path: "clusters/cluster-1/pki/etcd" - intermediate: - rootPath: "clusters/cluster-1/pki/root" - exportedKey: false - generate: false - - - name: etcd-client - vault: - role: - name: "kubelet-client" - path: "clusters/cluster-1/pki/etcd" - - - name: etcd-peer - vault: - role: - name: "etcd-peer" - path: "clusters/cluster-1/pki/etcd" - - - name: etcd-server - vault: - role: - name: "etcd-server" - path: "clusters/cluster-1/pki/etcd" + server: "http://51.250.67.8:9200" + auth: + caBundle: "" + tlsInsecure: true + bootstrap: + tokenPath: /tmp/bootstrap + appRole: + name: "" + path: "clusters/cluster-1/pki/front-proxy" + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath + timeout: 15 certificates: - name: front-proxy-ca - spec: - isCa: true - issuerRef: - name: front-proxy-ca - hostPathCert: "/etc/kubernetes/pki/ca" - - - name: system:kube-apiserver-front-proxy-client - spec: - duration: 2160h - renewBefore: 360h - commonName: system:kube-apiserver-front-proxy-client - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 2048 - usages: - - client auth - issuerRef: - name: front-proxy-client - hostPathCert: "/etc/kubernetes/pki/certs/kube-apiserver/certs" - - - name: kube-ca - spec: - isCa: true - issuerRef: - name: root-ca - hostPathCert: "/etc/kubernetes/pki/ca" - - - name: system:kube-apiserver-server - spec: - duration: 2160h - renewBefore: 360h - commonName: system:kube-apiserver-server - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 2048 - usages: - - server auth - dnsNames: - - system:kube-apiserver-server - - "localhost" - - "kubernetes" - - "kubernetes.default" - - "kubernetes.default.svc" - - "kubernetes.default.svc.cluster" - - "kubernetes.default.svc.cluster.local" - - "api.cluster-1.example.com" - ipAddresses: - - "127.0.0.1" - - "127.0.1.1" - - "127.0.1.6" - - "29.64.0.1" - issuerRef: - name: kube-apiserver - hostPathCert: "/etc/kubernetes/pki/certs/kube-apiserver/certs" - trigger: - - systemctl stop kube-apiserver.service - httpsCheck: 127.0.0.1:6443 - - - name: system:kube-apiserver-kubelet-client - spec: - duration: 2160h - renewBefore: 360h - subject: - organizations: - - system:masters - commonName: system:kube-apiserver-kubelet-client - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 2048 - usages: - - client auth - issuerRef: - name: kube-apiserver-kubelet-client - hostPathCert: "/etc/kubernetes/pki/certs/kube-apiserver/certs" - - - name: system:kube-controller-manager-client - spec: - duration: 2160h - renewBefore: 360h - commonName: system:kube-controller-manager - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 2048 - usages: - - client auth - issuerRef: - name: kube-controller-manager-client - hostPathCert: "/etc/kubernetes/pki/certs/kube-controller-manager/certs" - - - name: system:kube-controller-manager-server - spec: - duration: 2160h - renewBefore: 360h - commonName: system:kube-controller-manager-server - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 2048 - usages: - - server auth - dnsNames: - - "localhost" - - "kube-controller-manager.default" - - "kube-controller-manager.default.svc" - - "kube-controller-manager.default.svc.cluster" - - "kube-controller-manager.default.svc.cluster.local" - ipAddresses: - - "127.0.0.1" - - "127.0.1.1" - - "127.0.1.6" - issuerRef: - name: kube-controller-manager-server - hostPathCert: "/etc/kubernetes/pki/certs/kube-controller-manager/certs" - trigger: - - systemctl stop kube-controller-manager.service - httpsCheck: 127.0.0.1:6443 - - - name: system:kube-scheduler-server - spec: - duration: 2160h - renewBefore: 360h - commonName: system:kube-scheduler-server - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 2048 - usages: - - server auth - dnsNames: - - "localhost" - - "kube-scheduler.default" - - "kube-scheduler.default.svc" - - "kube-scheduler.default.svc.cluster" - - "kube-scheduler.default.svc.cluster.local" - ipAddresses: - - "127.0.0.1" - - "127.0.1.1" - - "127.0.1.6" - issuerRef: - name: kube-scheduler-server - hostPathCert: "/etc/kubernetes/pki/certs/kube-scheduler/certs" - trigger: - - systemctl stop kube-scheduler.service - httpsCheck: 127.0.0.1:6443 - - - name: system:kube-scheduler-client - spec: - duration: 2160h - renewBefore: 360h - commonName: system:kube-scheduler - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 2048 - usages: - - client auth - issuerRef: - name: kube-scheduler-client - hostPathCert: "/etc/kubernetes/pki/certs/kube-scheduler/certs" - - - name: system:node:${ instance_name }.${ base_domain } - spec: - duration: 2160h - renewBefore: 360h - subject: - organizations: - - system:nodes - commonName: system:node:${ instance_name }.${ base_domain } - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 2048 - usages: - - client auth - issuerRef: - name: kubelet-client - hostPathCert: "/etc/kubernetes/pki/certs/kubelet/certs" - - - name: etcd-ca - spec: - isCa: true - issuerRef: - name: etcd-ca - hostPathCert: "/etc/kubernetes/pki/ca" - - - name: system:etcd-healthcheck-client - spec: - duration: 2160h - renewBefore: 360h - commonName: system:etcd-healthcheck-client - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 2048 - usages: - - client auth - issuerRef: - name: etcd-client - hostPathCert: "/etc/kubernetes/pki/certs/kubelet/etcd" - - - name: system:etcd-peer - spec: - duration: 2160h - renewBefore: 360h - commonName: system:etcd-peer - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 2048 - usages: - - server auth - - client auth - dnsNames: - - "localhost" - - "${ instance_name }.${base_domain}" - ipAddresses: - - "127.0.0.1" - - "127.0.1.1" - - "127.0.1.6" - issuerRef: - name: etcd-peer - hostPathCert: "/etc/kubernetes/pki/certs/etcd/certs" - trigger: - - systemctl stop etcd.service - httpsCheck: 127.0.0.1:2379 - - - name: system:etcd-server - spec: - duration: 2160h - renewBefore: 360h - commonName: system:etcd-server - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 2048 - usages: - - server auth - - client auth - dnsNames: - - "localhost" - - "${ instance_name }.${base_domain}" - ipAddresses: - - "127.0.0.1" - - "127.0.1.1" - - "127.0.1.6" - issuerRef: - name: etcd-server - hostPathCert: "/etc/kubernetes/pki/certs/etcd/certs" - trigger: - - systemctl stop etcd.service - httpsCheck: 127.0.0.1:2380 - - - name: system:kube-apiserver-etcd-client - spec: - duration: 2160h - renewBefore: 360h - commonName: system:kube-apiserver-etcd-client - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 2048 - usages: - - client auth - issuerRef: - name: etcd-client - hostPathCert: "/etc/kubernetes/pki/certs/kube-apiserver/certs" - -keys: - - name: system:kube-apiserver-sa - host_path: /etc/kubernetes/pki/certs/kube-apiserver/ - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 2048 - public: true - vault: - kv: "clusters/cluster-1/kv" + issuerRef: + name: front-proxy-ca + isCa: true + ca: + exportedKey: false + generate: false + vault: + role: "" + path: "clusters/cluster-1/pki/front-proxy" + rootCAPath: "clusters/cluster-1/pki/root" + hostPath: /tmp/front-proxy-ca + renewBefore: 1d + trigger: + - ls -al \ No newline at end of file diff --git a/internal/config/config.go b/internal/config/config.go index cdde7e7..a1f2863 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -45,12 +45,12 @@ func (s *config) GetNewConfig() (newCfg Config, err error) { continue } var cfg Config - if err = yaml.Unmarshal(data, cfg); err != nil { - zap.L().Error("unmurshal config file", zap.String("path", path), zap.Error(err)) + if err = yaml.Unmarshal(data, &cfg); err != nil { + zap.L().Error("unmarshal config file", zap.String("path", path), zap.Error(err)) continue } - newCfg.Issueres = append(newCfg.Issueres, cfg.Issueres...) + newCfg.Issuers = append(newCfg.Issuers, cfg.Issuers...) newCfg.Resource.Certificates = append(newCfg.Resource.Certificates, cfg.Resource.Certificates...) newCfg.Resource.Keys = append(newCfg.Resource.Keys, cfg.Resource.Keys...) s.oldConfig[path] = struct{}{} diff --git a/internal/config/types.go b/internal/config/types.go index 24ab2a4..45ee644 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -3,7 +3,7 @@ package config import "time" type Config struct { - Issueres []Issuer `yaml:"issueres"` + Issuers []Issuer `yaml:"issuers"` Resource Resources `yaml:",inline"` } diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 998b9fc..26f3eea 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -59,6 +59,10 @@ func (s *controller) Start() { } func (s *controller) RefreshResource() { + if err := s.getNewResource(); err != nil { + zap.L().Error("refresh resources", zap.Error(err)) + } + t := time.NewTicker(30 * time.Second) defer t.Stop() for range t.C { @@ -74,7 +78,7 @@ func (s *controller) getNewResource() error { return fmt.Errorf("get new configs: %w", err) } - for _, vaultCfg := range cfg.Issueres { + for _, vaultCfg := range cfg.Issuers { // TODO: что делать если приходит несколько issuer с одинаковыми именами _, isExist := s.resource.Load(vaultCfg.Name) if isExist { diff --git a/test.example.yaml b/test.example.yaml deleted file mode 100644 index 60db0fa..0000000 --- a/test.example.yaml +++ /dev/null @@ -1,120 +0,0 @@ ---- -global: - vault: - serever: "http://${VAULT_IP}" # rename $address - caBundle: "" # new (сертификат для подключения к волту - при http не должен фигурировать) - tlsInsecure: true # new при указании тру скипать ssl верификацию - auth: - bootstrap: - token: "" # rename $bootstrap_token - appRole: - name: test-role # rename $approle_name - path: clusters/cluster-1/approle # rename $approle_path - roleIDLocalPath: "$PATH" # rename $local_path_to_role_id - SecretIDLocalPath: "$PATH" # rename $local_path_to_secret_id - kv: - path: "clusters/${cluster_name}/kv" - -issuers: - - name: kube-apiserver-server - vault: # Все переменные global.Vault.* могут быть переопределены тут в блоке vault - role: - name: "system_masters_client" # альтернатива блоку csr[*].role - path: "clusters/cluster-1/pki/kube-apiserver" # альтернатива блоку csr[*].cert_path - serever: "http://${VAULT_IP}" # rename $address - caBundle: "" # new (сертификат для подключения к волту - при http не должен фигурировать) - tlsInsecure: true # new при указании тру скипать ssl верификацию - auth: - bootstrap: - token: "" # rename $bootstrap_token - appRole: - name: test-role # rename $approle_name - path: clusters/cluster-1/approle # rename $approle_path - roleIdPath: "$PATH" # rename $local_path_to_role_id - secretIdPath: "$PATH" # rename $local_path_to_secret_id - - - name: kube-apiserver-ca - vault: # Все переменные global.Vault.* могут быть переопределены тут в блоке vault - role: - name: "kube-apiserver-ca" # альтернатива блоку csr[*].role - path: "clusters/cluster-1/pki/kube-apiserver" # альтернатива блоку csr[*].cert_path - # Если в сертификате указан isCA=true то смотреть в блок intermediate за до параметрами, во всех других игнорировать. - intermediate: # Альтернатива блоку certificates.intermediate_ca - rootPath: "clusters/cluster-1/pki/root" - exportedKey: false - generate: - false - # при указании generate: false в сертификате игнорируются поля ниже т.к ЦА уже создан и нам нужен публичный ключ. - # subject: # https://www.vaultproject.io/api-docs/secret/pki - # # vault write pki/issue/example_role organization="example.inc" ou="development team" country="EX" - # organizations: [] - # ous: [] - # countries: [] - # commonName: kube-apiserver-ca - # privateKey: - # algorithm: RSA - # encoding: PKCS1 - # size: 2048 - -certificates: - - name: kube-apiserver-server - spec: - lifespan: 2160h # на какой промежуток времени заказывается сертификат - renewBefore: 360h # за сколько до истечения надо перевыпустить - subject: # https://www.vaultproject.io/api-docs/secret/pki - # vault write pki/issue/example_role organization="example.inc" ou="development team" country="EX" - organizations: - - system:masters - ous: [] - countries: [] - commonName: kube-apiserver-server - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 2048 - usages: - - server auth - - client auth - dnsNames: - - kube-apiserver-server - - www.example.com - ipAddresses: - - 127.0.0.1 - issuerRef: - name: kube-apiserver-server - hostPath: "/etc/kubernetes/pki/certs/kube-apiserver/cert" - trigger: - - systemctl stop kube-apiserver.service - - - name: kube-apiserver-ca - spec: - lifespan: 2160h # на какой промежуток времени заказывается сертификат - renewBefore: 360h # за сколько до истечения надо перевыпустить - subject: # https://www.vaultproject.io/api-docs/secret/pki - # vault write pki/issue/example_role organization="example.inc" ou="development team" country="EX" - organizations: [] - ous: [] - countries: [] - commonName: kube-apiserver-ca - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 2048 - isCa: true - issuerRef: - name: kube-apiserver-ca - hostPath: "/etc/kubernetes/pki/ca" - trigger: - - systemctl stop kube-apiserver.service - -keys: - - name: system:kube-apiserver-sa - hostPath: /etc/kubernetes/pki/certs/kube-apiserver/ # join(hostPath,name) - privateKey: # добавить возможность менять тип и сайз - algorithm: RSA - encoding: PKCS1 - size: 2048 - public: true # если false генерил локально, true генерил локально и пушил в vault - vault: - kv: - path: "clusters/${cluster_name}/kv" From 18555eb21cc370ada7da7a5b6a7a869a03945c0f Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 30 Aug 2022 17:20:17 +0300 Subject: [PATCH 106/220] up --- example.yaml | 8 ++++---- internal/config/types.go | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/example.yaml b/example.yaml index afaee03..dce6fac 100644 --- a/example.yaml +++ b/example.yaml @@ -4,16 +4,16 @@ issuers: vault: server: "http://51.250.67.8:9200" auth: - caBundle: "" + caBundle: "approle" tlsInsecure: true bootstrap: - tokenPath: /tmp/bootstrap + token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ appRole: name: "" path: "clusters/cluster-1/pki/front-proxy" roleIDLocalPath: /tmp/keep/roleIDLocalPath secretIDLocalPath: /tmp/keep/secretIDLocalPath - timeout: 15 + timeout: 15s certificates: - name: front-proxy-ca @@ -28,6 +28,6 @@ certificates: path: "clusters/cluster-1/pki/front-proxy" rootCAPath: "clusters/cluster-1/pki/root" hostPath: /tmp/front-proxy-ca - renewBefore: 1d + renewBefore: 24h trigger: - ls -al \ No newline at end of file diff --git a/internal/config/types.go b/internal/config/types.go index 45ee644..acb01b8 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -13,8 +13,8 @@ type Issuer struct { } type Resources struct { - Certificates []Certificate `yaml:"certificate"` - Keys []Key `yaml:"key"` + Certificates []Certificate `yaml:"certificates"` + Keys []Key `yaml:"keys"` } type Certificate struct { @@ -47,7 +47,7 @@ type CA struct { } type Vault struct { - Server string `yaml:"address"` + Server string `yaml:"server"` Auth Auth `yaml:"auth"` KV KV `yaml:"kv"` Timeout time.Duration `yaml:"timeout"` From 071180a64f50d97c94a81007310551ffdedbdb3e Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 30 Aug 2022 20:31:22 +0300 Subject: [PATCH 107/220] up --- example.yaml | 18 +++++++++-------- internal/controller/controller.go | 1 - internal/resource/ca.go | 12 +++++------ internal/resource/csr.go | 4 ++-- internal/resource/resource.go | 3 +++ internal/resource/store.go | 33 ++++++------------------------- 6 files changed, 27 insertions(+), 44 deletions(-) diff --git a/example.yaml b/example.yaml index dce6fac..8557754 100644 --- a/example.yaml +++ b/example.yaml @@ -4,15 +4,15 @@ issuers: vault: server: "http://51.250.67.8:9200" auth: - caBundle: "approle" + caBundle: "" tlsInsecure: true bootstrap: token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ appRole: - name: "" - path: "clusters/cluster-1/pki/front-proxy" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath + name: "test-role" + path: "clusters/cluster-1/approle" + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath timeout: 15s certificates: @@ -23,11 +23,13 @@ certificates: ca: exportedKey: false generate: false + spec: + commonName: front-proxy vault: role: "" path: "clusters/cluster-1/pki/front-proxy" rootCAPath: "clusters/cluster-1/pki/root" - hostPath: /tmp/front-proxy-ca + hostPath: /tmp/keep/certs/front-proxy-ca renewBefore: 24h - trigger: - - ls -al \ No newline at end of file + trigger: + - ls -al diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 26f3eea..0a388a7 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -62,7 +62,6 @@ func (s *controller) RefreshResource() { if err := s.getNewResource(); err != nil { zap.L().Error("refresh resources", zap.Error(err)) } - t := time.NewTicker(30 * time.Second) defer t.Stop() for range t.C { diff --git a/internal/resource/ca.go b/internal/resource/ca.go index ded36b6..0d1db1d 100644 --- a/internal/resource/ca.go +++ b/internal/resource/ca.go @@ -1,7 +1,7 @@ package resource import ( - "crypto/tls" + "crypto/x509" "fmt" "path" "time" @@ -18,7 +18,7 @@ func (s *resource) checkCA(cert config.Certificate) { ) defer func() { - if err := s.storeCertificate(cert.HostPath, crt, key); err != nil { + if err := s.storeKeyPair(cert.HostPath, crt, key); err != nil { zap.L().Error( "stored intermediate-ca", zap.Error(err), @@ -28,13 +28,13 @@ func (s *resource) checkCA(cert config.Certificate) { crt, key, err = s.readCA(cert.Vault.Path) if err == nil { - var ca *tls.Certificate - ca, err = parseToCert(crt, key) + var ca *x509.Certificate + ca, err = x509.ParseCertificate(crt) if err != nil { err = fmt.Errorf("parse : %w", err) } - if ca != nil && time.Until(ca.Leaf.NotAfter) < cert.RenewBefore { - err = fmt.Errorf("expired until(h) %f", time.Until(ca.Leaf.NotAfter).Hours()) + if ca != nil && time.Until(ca.NotAfter) < cert.RenewBefore { + err = fmt.Errorf("expired until(h) %f", time.Until(ca.NotAfter).Hours()) } } diff --git a/internal/resource/csr.go b/internal/resource/csr.go index 7a878e3..4637066 100644 --- a/internal/resource/csr.go +++ b/internal/resource/csr.go @@ -15,7 +15,7 @@ import ( func (s *resource) checkCSR(i config.Certificate) { csr, err := s.readCertificate(i.HostPath) - if csr != nil && time.Until(csr.Leaf.NotAfter) > i.RenewBefore { + if csr != nil && time.Until(csr.NotAfter) > i.RenewBefore { return } if err != nil && !os.IsNotExist(err) { @@ -31,7 +31,7 @@ func (s *resource) checkCSR(i config.Certificate) { ) } - if err = s.storeCertificate(i.HostPath, cert, key); err != nil { + if err = s.storeKeyPair(i.HostPath, cert, key); err != nil { zap.L().Error( "store csr", zap.String("common_name", i.Spec.CommonName), diff --git a/internal/resource/resource.go b/internal/resource/resource.go index 1daf56e..0601b45 100644 --- a/internal/resource/resource.go +++ b/internal/resource/resource.go @@ -25,6 +25,7 @@ func Preparing( } func (s *resource) Check() { + zap.L().Debug("checking") wg := &sync.WaitGroup{} zap.L().Debug("certificate-intermediate-ca") @@ -51,6 +52,8 @@ func (s *resource) Check() { }(key) } wg.Wait() + + zap.L().Debug("done") } func (s *resource) Add(r config.Resources) { diff --git a/internal/resource/store.go b/internal/resource/store.go index d000721..f0b6a57 100644 --- a/internal/resource/store.go +++ b/internal/resource/store.go @@ -1,7 +1,6 @@ package resource import ( - "crypto/tls" "crypto/x509" "fmt" "os" @@ -19,7 +18,7 @@ func (s *resource) storeKey(path string, privare, public []byte) error { return nil } -func (s *resource) storeCertificate(path string, crt, key []byte) error { +func (s *resource) storeKeyPair(path string, crt, key []byte) error { if crt != nil { if err := os.WriteFile(path+".pem", crt, 0644); err != nil { return fmt.Errorf("failed to save certificate with path %s: %w", path, err) @@ -34,22 +33,18 @@ func (s *resource) storeCertificate(path string, crt, key []byte) error { return nil } -func (s *resource) readCertificate(path string) (*tls.Certificate, error) { +func (s *resource) readCertificate(path string) (*x509.Certificate, error) { crt, err := os.ReadFile(path + ".pem") if err != nil { return nil, err } - key, err := os.ReadFile(path + "-key.pem") - if err != nil { - return nil, err - } - return parseToCert(crt, key) + return x509.ParseCertificate(crt) } -func (s *resource) readCA(vaulPath string) (crt, key []byte, err error) { - vaulPath = path.Join(vaulPath, "cert/ca_chain") - ica, err := s.vault.Read(vaulPath) +func (s *resource) readCA(vaultPath string) (crt, key []byte, err error) { + vaultPath = path.Join(vaultPath, "cert/ca_chain") + ica, err := s.vault.Read(vaultPath) if ica != nil { if c, ok := ica["certificate"]; ok { crt = []byte(c.(string)) @@ -60,19 +55,3 @@ func (s *resource) readCA(vaulPath string) (crt, key []byte, err error) { } return } - -func parseToCert(crt, key []byte) (*tls.Certificate, error) { - cert, err := tls.X509KeyPair(crt, key) - if err != nil { - return nil, fmt.Errorf("failed to parse x509 key pair: %w", err) - } - if len(cert.Certificate) == 0 { - return nil, fmt.Errorf("list of certificates is empty") - } - - cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0]) - if err != nil { - return nil, err - } - return &cert, nil -} From 0c7de41860135663b2a720de5742190d432d4816 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 30 Aug 2022 20:48:26 +0300 Subject: [PATCH 108/220] fix x509 --- internal/resource/ca.go | 14 ++++++++------ internal/resource/csr.go | 24 ++++++++++++------------ 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/internal/resource/ca.go b/internal/resource/ca.go index 0d1db1d..912279b 100644 --- a/internal/resource/ca.go +++ b/internal/resource/ca.go @@ -2,6 +2,7 @@ package resource import ( "crypto/x509" + "encoding/pem" "fmt" "path" "time" @@ -29,7 +30,8 @@ func (s *resource) checkCA(cert config.Certificate) { crt, key, err = s.readCA(cert.Vault.Path) if err == nil { var ca *x509.Certificate - ca, err = x509.ParseCertificate(crt) + pBlock, _ := pem.Decode(crt) + ca, err = x509.ParseCertificate(pBlock.Bytes) if err != nil { err = fmt.Errorf("parse : %w", err) } @@ -41,7 +43,7 @@ func (s *resource) checkCA(cert config.Certificate) { if err != nil { zap.L().Warn( "intermediate ca", - zap.String("common_name", cert.Spec.CommonName+"-ca"), + zap.String("name", cert.Name), zap.Error(err), ) } else { @@ -53,14 +55,14 @@ func (s *resource) checkCA(cert config.Certificate) { if err != nil { zap.L().Error( "generate intermediate-ca", - zap.String("common_name", cert.Spec.CommonName), + zap.String("name", cert.Name), zap.Error(err), ) return } else { zap.L().Info( "intermediate-ca generated", - zap.String("common_name", cert.Spec.CommonName), + zap.String("name", cert.Name), ) } } @@ -69,8 +71,8 @@ func (s *resource) checkCA(cert config.Certificate) { func (s *resource) generateCA(cert config.Certificate) (crt, key []byte, err error) { // create intermediate ca csrData := map[string]interface{}{ - "common_name": fmt.Sprintf("%s Intermediate Authority", cert.Spec.CommonName), - "ttl": cert.Spec.TTL, + "name": fmt.Sprintf("%s Intermediate Authority", cert.Name), + "ttl": cert.Spec.TTL, } keyType := "internal" diff --git a/internal/resource/csr.go b/internal/resource/csr.go index 4637066..953cafb 100644 --- a/internal/resource/csr.go +++ b/internal/resource/csr.go @@ -13,49 +13,49 @@ import ( "github.com/fraima/key-keeper/internal/config" ) -func (s *resource) checkCSR(i config.Certificate) { - csr, err := s.readCertificate(i.HostPath) - if csr != nil && time.Until(csr.NotAfter) > i.RenewBefore { +func (s *resource) checkCSR(cert config.Certificate) { + csr, err := s.readCertificate(cert.HostPath) + if csr != nil && time.Until(csr.NotAfter) > cert.RenewBefore { return } if err != nil && !os.IsNotExist(err) { - zap.L().Error("read csr", zap.String("path", i.HostPath), zap.Error(err)) + zap.L().Error("read csr", zap.String("path", cert.HostPath), zap.Error(err)) } - cert, key, err := s.generateCSR(i) + crt, key, err := s.generateCSR(cert) if err != nil { zap.L().Error( "generate csr", - zap.String("common_name", i.Spec.CommonName), + zap.String("name", cert.Name), zap.Error(err), ) } - if err = s.storeKeyPair(i.HostPath, cert, key); err != nil { + if err = s.storeKeyPair(cert.HostPath, crt, key); err != nil { zap.L().Error( "store csr", - zap.String("common_name", i.Spec.CommonName), + zap.String("name", cert.Name), zap.Error(err), ) return } - for _, command := range i.Trigger { + for _, command := range cert.Trigger { cmd := strings.Split(command, " ") err := exec.Command(cmd[0], cmd[1:]...).Run() zap.L().Error( "csr trigger", - zap.String("common_name", i.Spec.CommonName), + zap.String("name", cert.Name), zap.String("command", command), zap.Error(err), ) } - zap.L().Info("csr generated", zap.String("common_name", i.Spec.CommonName)) + zap.L().Info("csr generated", zap.String("name", cert.Name)) } func (s *resource) generateCSR(i config.Certificate) ([]byte, []byte, error) { certData := map[string]interface{}{ - "common_name": i.Spec.CommonName, + "name": i.Name, "alt_names": strings.Join(i.Spec.Hostnames, ","), "ip_sans": strings.Join(i.Spec.IPAddresses, ","), } From 32572077c7048c5f930d22bcb59960bc4ed57a6b Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 30 Aug 2022 21:13:27 +0300 Subject: [PATCH 109/220] fix csr --- example.yaml | 52 +++++++++++++++++++++++++++++++---- internal/resource/resource.go | 8 ++---- 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/example.yaml b/example.yaml index 8557754..c68e3c8 100644 --- a/example.yaml +++ b/example.yaml @@ -11,8 +11,26 @@ issuers: appRole: name: "test-role" path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath + timeout: 15s + + - name: kube-apiserver-server + vault: + role: + name: "kube-apiserver" + path: "clusters/cluster-1/pki/kubernetes" + server: "http://51.250.67.8:9200" + auth: + caBundle: "" + tlsInsecure: true + bootstrap: + token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ + appRole: + name: "test-role" + path: "clusters/cluster-1/approle" + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath timeout: 15s certificates: @@ -23,13 +41,37 @@ certificates: ca: exportedKey: false generate: false - spec: - commonName: front-proxy vault: role: "" path: "clusters/cluster-1/pki/front-proxy" rootCAPath: "clusters/cluster-1/pki/root" hostPath: /tmp/keep/certs/front-proxy-ca renewBefore: 24h - trigger: + trigger: - ls -al + + - name: kube-apiserver-server + spec: + subject: + organizations: + - system:masters + ous: [] + countries: [] + commonName: kube-apiserver-server + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 2048 + usages: + - server auth + - client auth + dnsNames: + - kube-apiserver-server + - www.example.com + ipAddresses: + - 127.0.0.1 + issuerRef: + name: kube-apiserver-server + hostPath: "/tmp/keep/certs/kube-apiserver/cert" + trigger: + - systemctl stop kube-apiserver.service \ No newline at end of file diff --git a/internal/resource/resource.go b/internal/resource/resource.go index 0601b45..89739f7 100644 --- a/internal/resource/resource.go +++ b/internal/resource/resource.go @@ -34,12 +34,10 @@ func (s *resource) Check() { go func(c config.Certificate) { defer wg.Done() if c.IsCA { - if c.IsCA { - s.checkCA(c) - } else { - s.checkCSR(c) - } + s.checkCA(c) + return } + s.checkCSR(c) }(cert) } wg.Wait() From 3906e050454f3c89e7b2a7e2888e989266e4cc0f Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 30 Aug 2022 21:57:55 +0300 Subject: [PATCH 110/220] fix --- internal/resource/csr.go | 14 +++++++------- internal/resource/store.go | 4 +++- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/internal/resource/csr.go b/internal/resource/csr.go index 953cafb..fcdb16d 100644 --- a/internal/resource/csr.go +++ b/internal/resource/csr.go @@ -53,17 +53,17 @@ func (s *resource) checkCSR(cert config.Certificate) { zap.L().Info("csr generated", zap.String("name", cert.Name)) } -func (s *resource) generateCSR(i config.Certificate) ([]byte, []byte, error) { +func (s *resource) generateCSR(crt config.Certificate) ([]byte, []byte, error) { certData := map[string]interface{}{ - "name": i.Name, - "alt_names": strings.Join(i.Spec.Hostnames, ","), - "ip_sans": strings.Join(i.Spec.IPAddresses, ","), + "name": crt.Name, + "alt_names": strings.Join(crt.Spec.Hostnames, ","), + "ip_sans": strings.Join(crt.Spec.IPAddresses, ","), } - path := path.Join(i.Vault.Path, "issue", i.Vault.Role) - cert, err := s.vault.Write(path, certData) + path := path.Join(crt.Vault.Path, "issue", crt.Vault.Role) + csr, err := s.vault.Write(path, certData) if err != nil { return nil, nil, fmt.Errorf("generate with path %s : %w", path, err) } - return []byte(cert["certificate"].(string)), []byte(cert["private_key"].(string)), nil + return []byte(csr["certificate"].(string)), []byte(csr["private_key"].(string)), nil } diff --git a/internal/resource/store.go b/internal/resource/store.go index f0b6a57..ff4f7dd 100644 --- a/internal/resource/store.go +++ b/internal/resource/store.go @@ -2,6 +2,7 @@ package resource import ( "crypto/x509" + "encoding/pem" "fmt" "os" "path" @@ -39,7 +40,8 @@ func (s *resource) readCertificate(path string) (*x509.Certificate, error) { return nil, err } - return x509.ParseCertificate(crt) + pBlock, _ := pem.Decode(crt) + return x509.ParseCertificate(pBlock.Bytes) } func (s *resource) readCA(vaultPath string) (crt, key []byte, err error) { From 11b5fbfde23b6b7fcc7ef921f3f7e55959bdc2e2 Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Tue, 30 Aug 2022 23:50:36 +0300 Subject: [PATCH 111/220] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example.yaml | 4 +- test.yaml | 541 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 543 insertions(+), 2 deletions(-) create mode 100644 test.yaml diff --git a/example.yaml b/example.yaml index c68e3c8..dea3e7a 100644 --- a/example.yaml +++ b/example.yaml @@ -7,7 +7,7 @@ issuers: caBundle: "" tlsInsecure: true bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ + token: $TOKEN appRole: name: "test-role" path: "clusters/cluster-1/approle" @@ -25,7 +25,7 @@ issuers: caBundle: "" tlsInsecure: true bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ + token: $TOKEN appRole: name: "test-role" path: "clusters/cluster-1/approle" diff --git a/test.yaml b/test.yaml new file mode 100644 index 0000000..7e34796 --- /dev/null +++ b/test.yaml @@ -0,0 +1,541 @@ +--- +issuers: + - name: front-proxy-ca + vault: + server: "http://51.250.67.8:9200" + auth: + caBundle: "" + tlsInsecure: true + bootstrap: + token: $TOKEN + appRole: + name: "test-role" + path: "clusters/cluster-1/approle" + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath + timeout: 15s + + - name: front-proxy-client + vault: + server: "http://51.250.67.8:9200" + auth: + caBundle: "" + tlsInsecure: true + bootstrap: + token: $TOKEN + appRole: + name: "test-role" + path: "clusters/cluster-1/approle" + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath + timeout: 15s + + - name: kubernetes-ca + vault: + server: "http://51.250.67.8:9200" + auth: + caBundle: "" + tlsInsecure: true + bootstrap: + token: $TOKEN + appRole: + name: "test-role" + path: "clusters/cluster-1/approle" + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath + timeout: 15s + + - name: kube-apiserver-server + vault: + role: + name: "kube-apiserver" + path: "clusters/cluster-1/pki/kubernetes" + server: "http://51.250.67.8:9200" + auth: + caBundle: "" + tlsInsecure: true + bootstrap: + token: $TOKEN + appRole: + name: "test-role" + path: "clusters/cluster-1/approle" + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath + timeout: 15s + + - name: kube-apiserver-kubelet-client + vault: + role: + name: "kube-apiserver" + path: "clusters/cluster-1/pki/kubernetes" + server: "http://51.250.67.8:9200" + auth: + caBundle: "" + tlsInsecure: true + bootstrap: + token: $TOKEN + appRole: + name: "test-role" + path: "clusters/cluster-1/approle" + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath + timeout: 15s + + - name: kube-controller-manager-client + vault: + role: + name: "kube-controller-manager-client" + path: "clusters/cluster-1/pki/kubernetes" + server: "http://51.250.67.8:9200" + auth: + caBundle: "" + tlsInsecure: true + bootstrap: + token: $TOKEN + appRole: + name: "test-role" + path: "clusters/cluster-1/approle" + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath + timeout: 15s + + - name: kube-controller-manager-server + vault: + role: + name: "kube-controller-manager-server" + path: "clusters/cluster-1/pki/kubernetes" + server: "http://51.250.67.8:9200" + auth: + caBundle: "" + tlsInsecure: true + bootstrap: + token: $TOKEN + appRole: + name: "test-role" + path: "clusters/cluster-1/approle" + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath + timeout: 15s + + - name: kube-scheduler-server + vault: + role: + name: "kube-scheduler-server" + path: "clusters/cluster-1/pki/kubernetes" + server: "http://51.250.67.8:9200" + auth: + caBundle: "" + tlsInsecure: true + bootstrap: + token: $TOKEN + appRole: + name: "test-role" + path: "clusters/cluster-1/approle" + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath + timeout: 15s + + - name: kube-scheduler-client + vault: + role: + name: "kube-scheduler-client" + path: "clusters/cluster-1/pki/kubernetes" + server: "http://51.250.67.8:9200" + auth: + caBundle: "" + tlsInsecure: true + bootstrap: + token: $TOKEN + appRole: + name: "test-role" + path: "clusters/cluster-1/approle" + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath + timeout: 15s + + - name: kubelet-client + vault: + role: + name: "kubelet-client" + path: "clusters/cluster-1/pki/kubernetes" + server: "http://51.250.67.8:9200" + auth: + caBundle: "" + tlsInsecure: true + bootstrap: + token: $TOKEN + appRole: + name: "test-role" + path: "clusters/cluster-1/approle" + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath + timeout: 15s + + - name: etcd-ca + vault: + server: "http://51.250.67.8:9200" + auth: + caBundle: "" + tlsInsecure: true + bootstrap: + token: $TOKEN + appRole: + name: "test-role" + path: "clusters/cluster-1/approle" + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath + timeout: 15s + + - name: etcd-peer + vault: + role: + name: "etcd-peer" + path: "clusters/cluster-1/pki/etcd" + server: "http://51.250.67.8:9200" + auth: + caBundle: "" + tlsInsecure: true + bootstrap: + token: $TOKEN + appRole: + name: "test-role" + path: "clusters/cluster-1/approle" + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath + timeout: 15s + + - name: etcd-server + vault: + role: + name: "etcd-server" + path: "clusters/cluster-1/pki/etcd" + server: "http://51.250.67.8:9200" + auth: + caBundle: "" + tlsInsecure: true + bootstrap: + token: $TOKEN + appRole: + name: "test-role" + path: "clusters/cluster-1/approle" + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath + timeout: 15s + + - name: etcd-client + vault: + role: + name: "etcd-client" + path: "clusters/cluster-1/pki/etcd" + server: "http://51.250.67.8:9200" + auth: + caBundle: "" + tlsInsecure: true + bootstrap: + token: $TOKEN + appRole: + name: "test-role" + path: "clusters/cluster-1/approle" + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath + timeout: 15s + +certificates: + - name: front-proxy-ca + issuerRef: + name: front-proxy-ca + isCa: true + ca: + exportedKey: false + generate: false + vault: + role: "" + path: "clusters/cluster-1/pki/front-proxy" + rootCAPath: "clusters/cluster-1/pki/root" + hostPath: /tmp/keep/certs/front-proxy-ca + renewBefore: 2160h + + - name: front-proxy-client + issuerRef: + name: front-proxy-client + vault: + role: "front-proxy-client" + path: "clusters/cluster-1/pki/front-proxy" + spec: + commonName: front-proxy-client + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 4096 + usages: + - client auth + ttl: 100d + renewBefore: 360h + hostPath: "/tmp/keep/certs/front-proxy-client" + + + - name: kubernetes-ca + issuerRef: + name: kubernetes-ca + isCa: true + ca: + exportedKey: false + generate: false + vault: + role: "" + path: "clusters/cluster-1/pki/kubernetes" + rootCAPath: "clusters/cluster-1/pki/root" + hostPath: /tmp/keep/certs/kubernetes-ca + renewBefore: 2160h + + - name: kube-apiserver-server + issuerRef: + name: kube-apiserver-server + vault: + role: "kube-apiserver" + path: "clusters/cluster-1/pki/kubernetes" + spec: + commonName: custom:kube-apiserver-server + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 4096 + usages: + - server auth + hostnames: + - "localhost" + - "kubernetes" + - "kubernetes.default" + - "kubernetes.default.svc" + - "kubernetes.default.svc.cluster" + - "kubernetes.default.svc.cluster.local" + - "api.cluster-1.dobry-kot.ru" + ipAddresses: + - 127.0.0.1 + ttl: 100d + hostPath: "/tmp/keep/certs/kube-apiserver-server" + + - name: kube-apiserver-kubelet-client + issuerRef: + name: kube-apiserver-kubelet-client + vault: + role: "kube-apiserver-kubelet-client" + path: "clusters/cluster-1/pki/kubernetes" + spec: + commonName: custom:kube-apiserver-kubelet-client + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 4096 + usages: + - client auth + subject: + organizationalUnits: + - system:masters + ttl: 100d + renewBefore: 360h + hostPath: "/tmp/keep/certs/kube-apiserver-kubelet-client" + + - name: kube-controller-manager-client + issuerRef: + name: kube-controller-manager-client + vault: + role: "kube-controller-manager-client" + path: "clusters/cluster-1/pki/kubernetes" + spec: + commonName: custom:kube-controller-manager-client + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 4096 + usages: + - client auth + ttl: 100d + renewBefore: 360h + hostPath: "/tmp/keep/certs/kube-controller-manager-client" + + - name: kube-controller-manager-server + issuerRef: + name: kube-controller-manager-server + vault: + role: "kube-controller-manager-server" + path: "clusters/cluster-1/pki/kubernetes" + spec: + commonName: custom:kube-controller-manager-server + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 4096 + usages: + - server auth + hostnames: + - "localhost" + - "kube-controller-manager.default" + - "kube-controller-manager.default.svc" + - "kube-controller-manager.default.svc.cluster" + - "kube-controller-manager.default.svc.cluster.local" + ipAddresses: + - "127.0.0.1" + - "127.0.1.1" + - "127.0.1.6" + ttl: 100d + hostPath: "/tmp/keep/certs/kube-controller-manager-server" + + - name: kube-scheduler-server + issuerRef: + name: kube-scheduler-server + vault: + role: "kube-scheduler-server" + path: "clusters/cluster-1/pki/kubernetes" + spec: + commonName: custom:kube-scheduler-server + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 4096 + usages: + - server auth + hostnames: + - "localhost" + - "kube-scheduler.default" + - "kube-scheduler.default.svc" + - "kube-scheduler.default.svc.cluster" + - "kube-scheduler.default.svc.cluster.local" + ipAddresses: + - "127.0.0.1" + - "127.0.1.1" + - "127.0.1.6" + ttl: 100d + hostPath: "/tmp/keep/certs/kube-scheduler-server" + + - name: kube-scheduler-client + issuerRef: + name: kube-scheduler-client + vault: + role: "kube-scheduler-client" + path: "clusters/cluster-1/pki/kubernetes" + spec: + commonName: system:kube-scheduler + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 4096 + usages: + - client auth + ttl: 100d + renewBefore: 360h + hostPath: "/tmp/keep/certs/kube-scheduler-client" + + - name: kubelet-client + issuerRef: + name: kubelet-client + vault: + role: "kubelet-client" + path: "clusters/cluster-1/pki/kubernetes" + spec: + commonName: system:node:${instance_name} + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 4096 + subject: + organizations: + - system:nodes + usages: + - client auth + ttl: 100d + renewBefore: 360h + hostPath: "/tmp/keep/certs/kubelet-client" + + + - name: etcd-ca + issuerRef: + name: etcd-ca + isCa: true + ca: + exportedKey: false + generate: false + vault: + role: "" + path: "clusters/cluster-1/pki/etcd" + rootCAPath: "clusters/cluster-1/pki/root" + hostPath: /tmp/keep/certs/etcd-ca + renewBefore: 2160h + + - name: etcd-peer + issuerRef: + name: etcd-peer + vault: + role: "etcd-peer" + path: "clusters/cluster-1/pki/etcd" + spec: + commonName: custom:etcd-peer + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 4096 + usages: + - server auth + - client auth + hostnames: + - "localhost" + - "${ instance_name }.${base_domain}" + ipAddresses: + - "127.0.0.1" + - "127.0.1.1" + - "127.0.1.6" + ttl: 100d + hostPath: "/tmp/keep/certs/etcd-peer" + + - name: etcd-server + issuerRef: + name: etcd-server + vault: + role: "etcd-server" + path: "clusters/cluster-1/pki/etcd" + spec: + commonName: custom:etcd-server + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 4096 + usages: + - server auth + hostnames: + - "localhost" + - "${ instance_name }.${base_domain}" + ipAddresses: + - "127.0.0.1" + - "127.0.1.1" + - "127.0.1.6" + ttl: 100d + hostPath: "/tmp/keep/certs/etcd-server" + + - name: etcd-kube-apiserver-client + issuerRef: + name: etcd-client + vault: + role: "etcd-client" + path: "clusters/cluster-1/pki/etcd" + spec: + commonName: custom:etcd-kube-apiserver-client + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 4096 + usages: + - client auth + ttl: 100d + renewBefore: 360h + hostPath: "/tmp/keep/certs/etcd-kube-apiserver-client" + +keys: + - name: kube-sa + host_path: /tmp/keep/certs/kube-sa + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 2048 + public: true + vault: + kv: "clusters/cluster-1/kv" \ No newline at end of file From e732f056deffb0d246098fd739e19c3eead731c0 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 1 Sep 2022 14:02:55 +0300 Subject: [PATCH 112/220] generation csr --- config-struct.yaml | 8 +- internal/config/types.go | 42 +++++------ internal/resource/ca.go | 6 +- internal/resource/csr.go | 69 ----------------- internal/resource/resource.go | 2 +- internal/resource/simple.go | 69 +++++++++++++++++ internal/resource/store.go | 59 --------------- internal/resource/utils.go | 134 ++++++++++++++++++++++++++++++++++ 8 files changed, 232 insertions(+), 157 deletions(-) delete mode 100644 internal/resource/csr.go create mode 100644 internal/resource/simple.go delete mode 100644 internal/resource/store.go create mode 100644 internal/resource/utils.go diff --git a/config-struct.yaml b/config-struct.yaml index ca4c005..7791f73 100644 --- a/config-struct.yaml +++ b/config-struct.yaml @@ -24,16 +24,16 @@ certificates: # Описывает список доступных certificates exportedKey: bool # запрашивать приватный ключ или нет generate: bool # генерить ЦА или запросить существующий CA spec: # блок описывающий certificate - commonName: string # CommonName is the common name as specified on the DER encoded CSR. If specified, this value must also be present in `dnsNames` or `ipAddresses`. This field must match the corresponding field on the DER encoded CSR. subject: # блок описывающий принадлежность certificate + commonName: string # CommonName is the common name as specified on the DER encoded CSR. If specified, this value must also be present in `dnsNames` or `ipAddresses`. This field must match the corresponding field on the DER encoded CSR. countries: list of string # Countries to be used on the Certificate. localities: list of string # Cities to be used on the Certificate. - organizationalUnits: list of string # Organizational Units to be used on the Certificate. organizations: list of string # Organizations to be used on the Certificate. - postalCodes: list of string # Postal codes to be used on the Certificate. + organizationalUnits: list of string # Organizational Units to be used on the Certificate. provinces: list of string # State/Provinces to be used on the Certificate. - serialNumber: string # Serial number to be used on the Certificate + postalCodes: list of string # Postal codes to be used on the Certificate. streetAddresses: list of string # Street addresses to be used on the Certificate. + serialNumber: string # Serial number to be used on the Certificate privateKey: # Options to control private keys used for the Certificate. algorithm: string # Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either `RSA`,`Ed25519` or `ECDSA` If `algorithm` is specified and `size` is not provided, key size of 256 will be used for `ECDSA` key algorithm and key size of 2048 will be used for `RSA` key algorithm. key size is ignored when using the `Ed25519` key algorithm. encoding: string # The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 and PKCS#8, respectively. Defaults to `PKCS1` if not specified. diff --git a/internal/config/types.go b/internal/config/types.go index acb01b8..5fc284e 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -76,30 +76,24 @@ type AppRole struct { } type Spec struct { - CommonName string `yaml:"commonName"` - Subject Subject `yaml:"subject"` - PrivateKey PrivateKey `yaml:"privateKey"` - Usages []string `yaml:"usages"` - Hostnames []string `yaml:"hostnames"` - IPAddresses []string `yaml:"ipAddresses"` - TTL string `yaml:"ttl"` -} - -type CertVault struct { - Role string `yaml:"role"` - Path string `yaml:"path"` - RootCAPath string `yaml:"rootCAPath"` + Subject Subject `yaml:"subject"` + PrivateKey PrivateKey `yaml:"privateKey"` + Usages []string `yaml:"usages"` + Hostnames []string `yaml:"hostnames"` + IPAddresses []string `yaml:"ipAddresses"` + TTL time.Duration `yaml:"ttl"` } type Subject struct { - Countries []string `yaml:"countries"` - Localities []string `yaml:"localities"` - OrganizationalUnits []string `yaml:"organizationalUnits"` - Organizations []string `yaml:"organizations"` - PostalCodes []string `yaml:"postalCodes"` - Provinces []string `yaml:"provinces"` - SerialNumber string `yaml:"serialNumber"` - StreetAddresses []string `yaml:"streetAddresses"` + CommonName string `yaml:"commonName"` + Country []string `yaml:"countries"` + Locality []string `yaml:"localities"` + Organization []string `yaml:"organizations"` + OrganizationalUnit []string `yaml:"organizationalUnits"` + Province []string `yaml:"provinces"` + PostalCode []string `yaml:"postalCodes"` + StreetAddress []string `yaml:"streetAddresses"` + SerialNumber string `yaml:"serialNumber"` } type PrivateKey struct { @@ -107,3 +101,9 @@ type PrivateKey struct { Encoding string `yaml:"encoding"` Size int `yaml:"size"` } + +type CertVault struct { + Role string `yaml:"role"` + Path string `yaml:"path"` + RootCAPath string `yaml:"rootCAPath"` +} diff --git a/internal/resource/ca.go b/internal/resource/ca.go index 912279b..2c96e1d 100644 --- a/internal/resource/ca.go +++ b/internal/resource/ca.go @@ -71,8 +71,8 @@ func (s *resource) checkCA(cert config.Certificate) { func (s *resource) generateCA(cert config.Certificate) (crt, key []byte, err error) { // create intermediate ca csrData := map[string]interface{}{ - "name": fmt.Sprintf("%s Intermediate Authority", cert.Name), - "ttl": cert.Spec.TTL, + "common_name": fmt.Sprintf("%s Intermediate Authority", cert.Name), + "ttl": cert.Spec.TTL, } keyType := "internal" @@ -83,7 +83,7 @@ func (s *resource) generateCA(cert config.Certificate) (crt, key []byte, err err vaultPath := path.Join(cert.Vault.Path, "intermediate/generate", keyType) csr, err := s.vault.Write(vaultPath, csrData) if err != nil { - err = fmt.Errorf("create: %w", err) + err = fmt.Errorf("generate: %w", err) return } diff --git a/internal/resource/csr.go b/internal/resource/csr.go deleted file mode 100644 index fcdb16d..0000000 --- a/internal/resource/csr.go +++ /dev/null @@ -1,69 +0,0 @@ -package resource - -import ( - "fmt" - "os" - "os/exec" - "path" - "strings" - "time" - - "go.uber.org/zap" - - "github.com/fraima/key-keeper/internal/config" -) - -func (s *resource) checkCSR(cert config.Certificate) { - csr, err := s.readCertificate(cert.HostPath) - if csr != nil && time.Until(csr.NotAfter) > cert.RenewBefore { - return - } - if err != nil && !os.IsNotExist(err) { - zap.L().Error("read csr", zap.String("path", cert.HostPath), zap.Error(err)) - } - - crt, key, err := s.generateCSR(cert) - if err != nil { - zap.L().Error( - "generate csr", - zap.String("name", cert.Name), - zap.Error(err), - ) - } - - if err = s.storeKeyPair(cert.HostPath, crt, key); err != nil { - zap.L().Error( - "store csr", - zap.String("name", cert.Name), - zap.Error(err), - ) - return - } - - for _, command := range cert.Trigger { - cmd := strings.Split(command, " ") - err := exec.Command(cmd[0], cmd[1:]...).Run() - zap.L().Error( - "csr trigger", - zap.String("name", cert.Name), - zap.String("command", command), - zap.Error(err), - ) - } - zap.L().Info("csr generated", zap.String("name", cert.Name)) -} - -func (s *resource) generateCSR(crt config.Certificate) ([]byte, []byte, error) { - certData := map[string]interface{}{ - "name": crt.Name, - "alt_names": strings.Join(crt.Spec.Hostnames, ","), - "ip_sans": strings.Join(crt.Spec.IPAddresses, ","), - } - path := path.Join(crt.Vault.Path, "issue", crt.Vault.Role) - csr, err := s.vault.Write(path, certData) - if err != nil { - return nil, nil, fmt.Errorf("generate with path %s : %w", path, err) - } - - return []byte(csr["certificate"].(string)), []byte(csr["private_key"].(string)), nil -} diff --git a/internal/resource/resource.go b/internal/resource/resource.go index 89739f7..0b2d1e1 100644 --- a/internal/resource/resource.go +++ b/internal/resource/resource.go @@ -37,7 +37,7 @@ func (s *resource) Check() { s.checkCA(c) return } - s.checkCSR(c) + s.checkCertificate(c) }(cert) } wg.Wait() diff --git a/internal/resource/simple.go b/internal/resource/simple.go new file mode 100644 index 0000000..ad7c411 --- /dev/null +++ b/internal/resource/simple.go @@ -0,0 +1,69 @@ +package resource + +import ( + "fmt" + "os" + "os/exec" + "path" + "strings" + "time" + + "go.uber.org/zap" + + "github.com/fraima/key-keeper/internal/config" +) + +func (s *resource) checkCertificate(cfg config.Certificate) { + cert, err := s.readCertificate(cfg.HostPath) + if cert != nil && time.Until(cert.NotAfter) > cfg.RenewBefore { + return + } + if err != nil && !os.IsNotExist(err) { + zap.L().Error("read csr", zap.String("path", cfg.HostPath), zap.Error(err)) + } + + crt, key, err := s.generateCertificate(cfg) + if err != nil { + zap.L().Error( + "generate csr", + zap.String("name", cfg.Name), + zap.Error(err), + ) + } + + if err = s.storeKeyPair(cfg.HostPath, crt, key); err != nil { + zap.L().Error( + "store csr", + zap.String("name", cfg.Name), + zap.Error(err), + ) + return + } + + for _, command := range cfg.Trigger { + cmd := strings.Split(command, " ") + err := exec.Command(cmd[0], cmd[1:]...).Run() + zap.L().Error( + "csr trigger", + zap.String("name", cfg.Name), + zap.String("command", command), + zap.Error(err), + ) + } + zap.L().Info("csr generated", zap.String("name", cfg.Name)) +} + +func (s *resource) generateCertificate(cfg config.Certificate) ([]byte, []byte, error) { + csr, key := createCSR(cfg.Spec) + + certData := map[string]interface{}{ + "pem_bundle": fmt.Sprintf("%s%s", csr, key), + } + path := path.Join(cfg.Vault.Path, "sign", cfg.Vault.Role) + cert, err := s.vault.Write(path, certData) + if err != nil { + return nil, nil, fmt.Errorf("generate with path %s : %w", path, err) + } + + return []byte(cert["certificate"].(string)), []byte(cert["private_key"].(string)), nil +} diff --git a/internal/resource/store.go b/internal/resource/store.go deleted file mode 100644 index ff4f7dd..0000000 --- a/internal/resource/store.go +++ /dev/null @@ -1,59 +0,0 @@ -package resource - -import ( - "crypto/x509" - "encoding/pem" - "fmt" - "os" - "path" -) - -func (s *resource) storeKey(path string, privare, public []byte) error { - if err := os.WriteFile(path+".pem", privare, 0600); err != nil { - return fmt.Errorf("failed to save privare key with path %s: %w", path, err) - } - - if err := os.WriteFile(path+".pub", public, 0600); err != nil { - return fmt.Errorf("failed to public key file: %w", err) - } - return nil -} - -func (s *resource) storeKeyPair(path string, crt, key []byte) error { - if crt != nil { - if err := os.WriteFile(path+".pem", crt, 0644); err != nil { - return fmt.Errorf("failed to save certificate with path %s: %w", path, err) - } - } - - if key != nil { - if err := os.WriteFile(path+"-key.pem", key, 0600); err != nil { - return fmt.Errorf("failed to save key file: %w", err) - } - } - return nil -} - -func (s *resource) readCertificate(path string) (*x509.Certificate, error) { - crt, err := os.ReadFile(path + ".pem") - if err != nil { - return nil, err - } - - pBlock, _ := pem.Decode(crt) - return x509.ParseCertificate(pBlock.Bytes) -} - -func (s *resource) readCA(vaultPath string) (crt, key []byte, err error) { - vaultPath = path.Join(vaultPath, "cert/ca_chain") - ica, err := s.vault.Read(vaultPath) - if ica != nil { - if c, ok := ica["certificate"]; ok { - crt = []byte(c.(string)) - } - if k, ok := ica["private_key"]; ok { - key = []byte(k.(string)) - } - } - return -} diff --git a/internal/resource/utils.go b/internal/resource/utils.go new file mode 100644 index 0000000..12b513d --- /dev/null +++ b/internal/resource/utils.go @@ -0,0 +1,134 @@ +package resource + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "fmt" + "math/big" + "net" + "net/url" + "os" + "path" + "time" + + "github.com/fraima/key-keeper/internal/config" +) + +func (s *resource) storeKey(path string, privare, public []byte) error { + if err := os.WriteFile(path+".pem", privare, 0600); err != nil { + return fmt.Errorf("failed to save privare key with path %s: %w", path, err) + } + + if err := os.WriteFile(path+".pub", public, 0600); err != nil { + return fmt.Errorf("failed to public key file: %w", err) + } + return nil +} + +func (s *resource) storeKeyPair(path string, crt, key []byte) error { + if crt != nil { + if err := os.WriteFile(path+".pem", crt, 0644); err != nil { + return fmt.Errorf("failed to save certificate with path %s: %w", path, err) + } + } + + if key != nil { + if err := os.WriteFile(path+"-key.pem", key, 0600); err != nil { + return fmt.Errorf("failed to save key file: %w", err) + } + } + return nil +} + +func (s *resource) readCertificate(path string) (*x509.Certificate, error) { + crt, err := os.ReadFile(path + ".pem") + if err != nil { + return nil, err + } + + pBlock, _ := pem.Decode(crt) + return x509.ParseCertificate(pBlock.Bytes) +} + +func (s *resource) readCA(vaultPath string) (crt, key []byte, err error) { + vaultPath = path.Join(vaultPath, "cert/ca_chain") + ica, err := s.vault.Read(vaultPath) + if ica != nil { + if c, ok := ica["certificate"]; ok { + crt = []byte(c.(string)) + } + if k, ok := ica["private_key"]; ok { + key = []byte(k.(string)) + } + } + return +} + +func createCSR(spec config.Spec) (crt, key []byte) { + pk, _ := rsa.GenerateKey(rand.Reader, spec.PrivateKey.Size) + + template := x509.Certificate{ + SerialNumber: big.NewInt(0), + Subject: pkix.Name{ + CommonName: spec.Subject.CommonName, + Country: spec.Subject.Country, + Locality: spec.Subject.Locality, + Organization: spec.Subject.Organization, + OrganizationalUnit: spec.Subject.OrganizationalUnit, + Province: spec.Subject.Province, + PostalCode: spec.Subject.PostalCode, + StreetAddress: spec.Subject.StreetAddress, + SerialNumber: spec.Subject.SerialNumber, + }, + IPAddresses: getIPAddresses(spec.IPAddresses), + URIs: getURLs(spec.Hostnames), + NotBefore: time.Now(), + NotAfter: time.Now().Add(spec.TTL), + BasicConstraintsValid: true, + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyAgreement | x509.KeyUsageKeyEncipherment | x509.KeyUsageDataEncipherment, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, + SignatureAlgorithm: x509.SHA256WithRSA, + } + + //Create certificate using templet + derBytes, _ := x509.CreateCertificate(rand.Reader, &template, &template, &pk.PublicKey, pk) + + //pem encoding of certificate + crt = pem.EncodeToMemory( + &pem.Block{ + Type: "CERTIFICATE", + Bytes: derBytes, + }, + ) + + key = pem.EncodeToMemory( + &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: derBytes, + }, + ) + return +} + +func getIPAddresses(ips []string) []net.IP { + ipAddresses := make([]net.IP, 0, len(ips)) + + for _, ip := range ips { + ipAddresses = append(ipAddresses, net.IP(ip)) + } + return ipAddresses +} + +func getURLs(hostnames []string) []*url.URL { + urls := make([]*url.URL, 0, len(hostnames)) + + for _, hostname := range hostnames { + // TODO: error handler + url, _ := url.Parse(hostname) + urls = append(urls, url) + } + return urls +} From fd218e5f34623f56e5744b4490a01a61bc841013 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 1 Sep 2022 17:43:44 +0300 Subject: [PATCH 113/220] up --- internal/config/types.go | 12 +- .../resource/{ca.go => ca-certificate.go} | 0 .../resource/{simple.go => certificate.go} | 6 +- internal/resource/utils.go | 45 +++--- test.yaml | 132 +++++++++--------- 5 files changed, 92 insertions(+), 103 deletions(-) rename internal/resource/{ca.go => ca-certificate.go} (100%) rename internal/resource/{simple.go => certificate.go} (93%) diff --git a/internal/config/types.go b/internal/config/types.go index 5fc284e..4563a74 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -76,12 +76,12 @@ type AppRole struct { } type Spec struct { - Subject Subject `yaml:"subject"` - PrivateKey PrivateKey `yaml:"privateKey"` - Usages []string `yaml:"usages"` - Hostnames []string `yaml:"hostnames"` - IPAddresses []string `yaml:"ipAddresses"` - TTL time.Duration `yaml:"ttl"` + Subject Subject `yaml:"subject"` + PrivateKey PrivateKey `yaml:"privateKey"` + Usages []string `yaml:"usages"` + Hostnames []string `yaml:"hostnames"` + IPAddresses []string `yaml:"ipAddresses"` + TTL string `yaml:"ttl"` } type Subject struct { diff --git a/internal/resource/ca.go b/internal/resource/ca-certificate.go similarity index 100% rename from internal/resource/ca.go rename to internal/resource/ca-certificate.go diff --git a/internal/resource/simple.go b/internal/resource/certificate.go similarity index 93% rename from internal/resource/simple.go rename to internal/resource/certificate.go index ad7c411..4a715b9 100644 --- a/internal/resource/simple.go +++ b/internal/resource/certificate.go @@ -54,11 +54,13 @@ func (s *resource) checkCertificate(cfg config.Certificate) { } func (s *resource) generateCertificate(cfg config.Certificate) ([]byte, []byte, error) { - csr, key := createCSR(cfg.Spec) + csr := createCSR(cfg.Spec) certData := map[string]interface{}{ - "pem_bundle": fmt.Sprintf("%s%s", csr, key), + "csr": string(csr), + "ttl": cfg.Spec.TTL, } + fmt.Println(string(csr)) path := path.Join(cfg.Vault.Path, "sign", cfg.Vault.Role) cert, err := s.vault.Write(path, certData) if err != nil { diff --git a/internal/resource/utils.go b/internal/resource/utils.go index 12b513d..5c0453f 100644 --- a/internal/resource/utils.go +++ b/internal/resource/utils.go @@ -7,12 +7,10 @@ import ( "crypto/x509/pkix" "encoding/pem" "fmt" - "math/big" "net" "net/url" "os" "path" - "time" "github.com/fraima/key-keeper/internal/config" ) @@ -70,8 +68,7 @@ func (s *resource) readCA(vaultPath string) (crt, key []byte, err error) { func createCSR(spec config.Spec) (crt, key []byte) { pk, _ := rsa.GenerateKey(rand.Reader, spec.PrivateKey.Size) - template := x509.Certificate{ - SerialNumber: big.NewInt(0), + template := x509.CertificateRequest{ Subject: pkix.Name{ CommonName: spec.Subject.CommonName, Country: spec.Subject.Country, @@ -83,34 +80,26 @@ func createCSR(spec config.Spec) (crt, key []byte) { StreetAddress: spec.Subject.StreetAddress, SerialNumber: spec.Subject.SerialNumber, }, - IPAddresses: getIPAddresses(spec.IPAddresses), - URIs: getURLs(spec.Hostnames), - NotBefore: time.Now(), - NotAfter: time.Now().Add(spec.TTL), - BasicConstraintsValid: true, - KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyAgreement | x509.KeyUsageKeyEncipherment | x509.KeyUsageDataEncipherment, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, - SignatureAlgorithm: x509.SHA256WithRSA, + IPAddresses: getIPAddresses(spec.IPAddresses), + URIs: getURIs(spec.Hostnames), + SignatureAlgorithm: x509.SHA256WithRSA, } - //Create certificate using templet - derBytes, _ := x509.CreateCertificate(rand.Reader, &template, &template, &pk.PublicKey, pk) + csr, _ := x509.CreateCertificateRequest(rand.Reader, &template, pk) //pem encoding of certificate - crt = pem.EncodeToMemory( - &pem.Block{ - Type: "CERTIFICATE", - Bytes: derBytes, - }, - ) + return pem.EncodeToMemory( + &pem.Block{ + Type: "CERTIFICATE REQUEST", + Bytes: csr, + }, + ), pem.EncodeToMemory( + &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(pk), + }, + ) - key = pem.EncodeToMemory( - &pem.Block{ - Type: "RSA PRIVATE KEY", - Bytes: derBytes, - }, - ) - return } func getIPAddresses(ips []string) []net.IP { @@ -122,7 +111,7 @@ func getIPAddresses(ips []string) []net.IP { return ipAddresses } -func getURLs(hostnames []string) []*url.URL { +func getURIs(hostnames []string) []*url.URL { urls := make([]*url.URL, 0, len(hostnames)) for _, hostname := range hostnames { diff --git a/test.yaml b/test.yaml index 7e34796..af2327d 100644 --- a/test.yaml +++ b/test.yaml @@ -7,12 +7,12 @@ issuers: caBundle: "" tlsInsecure: true bootstrap: - token: $TOKEN + token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ appRole: name: "test-role" path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath timeout: 15s - name: front-proxy-client @@ -22,12 +22,12 @@ issuers: caBundle: "" tlsInsecure: true bootstrap: - token: $TOKEN + token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ appRole: name: "test-role" path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath timeout: 15s - name: kubernetes-ca @@ -37,12 +37,12 @@ issuers: caBundle: "" tlsInsecure: true bootstrap: - token: $TOKEN + token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ appRole: name: "test-role" path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath timeout: 15s - name: kube-apiserver-server @@ -55,12 +55,12 @@ issuers: caBundle: "" tlsInsecure: true bootstrap: - token: $TOKEN + token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ appRole: name: "test-role" path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath timeout: 15s - name: kube-apiserver-kubelet-client @@ -73,12 +73,12 @@ issuers: caBundle: "" tlsInsecure: true bootstrap: - token: $TOKEN + token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ appRole: name: "test-role" path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath timeout: 15s - name: kube-controller-manager-client @@ -91,12 +91,12 @@ issuers: caBundle: "" tlsInsecure: true bootstrap: - token: $TOKEN + token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ appRole: name: "test-role" path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath timeout: 15s - name: kube-controller-manager-server @@ -109,12 +109,12 @@ issuers: caBundle: "" tlsInsecure: true bootstrap: - token: $TOKEN + token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ appRole: name: "test-role" path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath timeout: 15s - name: kube-scheduler-server @@ -127,12 +127,12 @@ issuers: caBundle: "" tlsInsecure: true bootstrap: - token: $TOKEN + token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ appRole: name: "test-role" path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath timeout: 15s - name: kube-scheduler-client @@ -145,12 +145,12 @@ issuers: caBundle: "" tlsInsecure: true bootstrap: - token: $TOKEN + token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ appRole: name: "test-role" path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath timeout: 15s - name: kubelet-client @@ -163,12 +163,12 @@ issuers: caBundle: "" tlsInsecure: true bootstrap: - token: $TOKEN + token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ appRole: name: "test-role" path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath timeout: 15s - name: etcd-ca @@ -178,12 +178,12 @@ issuers: caBundle: "" tlsInsecure: true bootstrap: - token: $TOKEN + token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ appRole: name: "test-role" path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath timeout: 15s - name: etcd-peer @@ -196,12 +196,12 @@ issuers: caBundle: "" tlsInsecure: true bootstrap: - token: $TOKEN + token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ appRole: name: "test-role" path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath timeout: 15s - name: etcd-server @@ -214,12 +214,12 @@ issuers: caBundle: "" tlsInsecure: true bootstrap: - token: $TOKEN + token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ appRole: name: "test-role" path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath timeout: 15s - name: etcd-client @@ -232,12 +232,12 @@ issuers: caBundle: "" tlsInsecure: true bootstrap: - token: $TOKEN + token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ appRole: name: "test-role" path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath + roleIDLocalPath: /tmp/keep/roleIDLocalPath + secretIDLocalPath: /tmp/keep/secretIDLocalPath timeout: 15s certificates: @@ -260,7 +260,7 @@ certificates: name: front-proxy-client vault: role: "front-proxy-client" - path: "clusters/cluster-1/pki/front-proxy" + path: "clusters/cluster-1/pki/front-proxy" spec: commonName: front-proxy-client privateKey: @@ -269,11 +269,10 @@ certificates: size: 4096 usages: - client auth - ttl: 100d + ttl: 100h renewBefore: 360h hostPath: "/tmp/keep/certs/front-proxy-client" - - name: kubernetes-ca issuerRef: name: kubernetes-ca @@ -293,7 +292,7 @@ certificates: name: kube-apiserver-server vault: role: "kube-apiserver" - path: "clusters/cluster-1/pki/kubernetes" + path: "clusters/cluster-1/pki/kubernetes" spec: commonName: custom:kube-apiserver-server privateKey: @@ -312,7 +311,7 @@ certificates: - "api.cluster-1.dobry-kot.ru" ipAddresses: - 127.0.0.1 - ttl: 100d + ttl: 100h hostPath: "/tmp/keep/certs/kube-apiserver-server" - name: kube-apiserver-kubelet-client @@ -320,7 +319,7 @@ certificates: name: kube-apiserver-kubelet-client vault: role: "kube-apiserver-kubelet-client" - path: "clusters/cluster-1/pki/kubernetes" + path: "clusters/cluster-1/pki/kubernetes" spec: commonName: custom:kube-apiserver-kubelet-client privateKey: @@ -332,7 +331,7 @@ certificates: subject: organizationalUnits: - system:masters - ttl: 100d + ttl: 100h renewBefore: 360h hostPath: "/tmp/keep/certs/kube-apiserver-kubelet-client" @@ -341,7 +340,7 @@ certificates: name: kube-controller-manager-client vault: role: "kube-controller-manager-client" - path: "clusters/cluster-1/pki/kubernetes" + path: "clusters/cluster-1/pki/kubernetes" spec: commonName: custom:kube-controller-manager-client privateKey: @@ -350,7 +349,7 @@ certificates: size: 4096 usages: - client auth - ttl: 100d + ttl: 100h renewBefore: 360h hostPath: "/tmp/keep/certs/kube-controller-manager-client" @@ -359,7 +358,7 @@ certificates: name: kube-controller-manager-server vault: role: "kube-controller-manager-server" - path: "clusters/cluster-1/pki/kubernetes" + path: "clusters/cluster-1/pki/kubernetes" spec: commonName: custom:kube-controller-manager-server privateKey: @@ -378,7 +377,7 @@ certificates: - "127.0.0.1" - "127.0.1.1" - "127.0.1.6" - ttl: 100d + ttl: 100h hostPath: "/tmp/keep/certs/kube-controller-manager-server" - name: kube-scheduler-server @@ -386,7 +385,7 @@ certificates: name: kube-scheduler-server vault: role: "kube-scheduler-server" - path: "clusters/cluster-1/pki/kubernetes" + path: "clusters/cluster-1/pki/kubernetes" spec: commonName: custom:kube-scheduler-server privateKey: @@ -405,7 +404,7 @@ certificates: - "127.0.0.1" - "127.0.1.1" - "127.0.1.6" - ttl: 100d + ttl: 100h hostPath: "/tmp/keep/certs/kube-scheduler-server" - name: kube-scheduler-client @@ -413,7 +412,7 @@ certificates: name: kube-scheduler-client vault: role: "kube-scheduler-client" - path: "clusters/cluster-1/pki/kubernetes" + path: "clusters/cluster-1/pki/kubernetes" spec: commonName: system:kube-scheduler privateKey: @@ -422,7 +421,7 @@ certificates: size: 4096 usages: - client auth - ttl: 100d + ttl: 100h renewBefore: 360h hostPath: "/tmp/keep/certs/kube-scheduler-client" @@ -431,7 +430,7 @@ certificates: name: kubelet-client vault: role: "kubelet-client" - path: "clusters/cluster-1/pki/kubernetes" + path: "clusters/cluster-1/pki/kubernetes" spec: commonName: system:node:${instance_name} privateKey: @@ -443,11 +442,10 @@ certificates: - system:nodes usages: - client auth - ttl: 100d + ttl: 100h renewBefore: 360h hostPath: "/tmp/keep/certs/kubelet-client" - - name: etcd-ca issuerRef: name: etcd-ca @@ -467,7 +465,7 @@ certificates: name: etcd-peer vault: role: "etcd-peer" - path: "clusters/cluster-1/pki/etcd" + path: "clusters/cluster-1/pki/etcd" spec: commonName: custom:etcd-peer privateKey: @@ -484,7 +482,7 @@ certificates: - "127.0.0.1" - "127.0.1.1" - "127.0.1.6" - ttl: 100d + ttl: 100h hostPath: "/tmp/keep/certs/etcd-peer" - name: etcd-server @@ -492,7 +490,7 @@ certificates: name: etcd-server vault: role: "etcd-server" - path: "clusters/cluster-1/pki/etcd" + path: "clusters/cluster-1/pki/etcd" spec: commonName: custom:etcd-server privateKey: @@ -508,7 +506,7 @@ certificates: - "127.0.0.1" - "127.0.1.1" - "127.0.1.6" - ttl: 100d + ttl: 100h hostPath: "/tmp/keep/certs/etcd-server" - name: etcd-kube-apiserver-client @@ -516,7 +514,7 @@ certificates: name: etcd-client vault: role: "etcd-client" - path: "clusters/cluster-1/pki/etcd" + path: "clusters/cluster-1/pki/etcd" spec: commonName: custom:etcd-kube-apiserver-client privateKey: @@ -525,7 +523,7 @@ certificates: size: 4096 usages: - client auth - ttl: 100d + ttl: 100h renewBefore: 360h hostPath: "/tmp/keep/certs/etcd-kube-apiserver-client" @@ -538,4 +536,4 @@ keys: size: 2048 public: true vault: - kv: "clusters/cluster-1/kv" \ No newline at end of file + kv: "clusters/cluster-1/kv" From a79c991698538b4b6cc84386f43ca0f4de5eb525 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 1 Sep 2022 17:56:45 +0300 Subject: [PATCH 114/220] up --- internal/resource/certificate.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/resource/certificate.go b/internal/resource/certificate.go index 4a715b9..d2b0f97 100644 --- a/internal/resource/certificate.go +++ b/internal/resource/certificate.go @@ -54,7 +54,7 @@ func (s *resource) checkCertificate(cfg config.Certificate) { } func (s *resource) generateCertificate(cfg config.Certificate) ([]byte, []byte, error) { - csr := createCSR(cfg.Spec) + csr, key := createCSR(cfg.Spec) certData := map[string]interface{}{ "csr": string(csr), @@ -67,5 +67,5 @@ func (s *resource) generateCertificate(cfg config.Certificate) ([]byte, []byte, return nil, nil, fmt.Errorf("generate with path %s : %w", path, err) } - return []byte(cert["certificate"].(string)), []byte(cert["private_key"].(string)), nil + return []byte(cert["certificate"].(string)), key, nil } From 8938cc36734b5a68c77256db87f8c36127c380af Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 1 Sep 2022 19:37:15 +0300 Subject: [PATCH 115/220] rename --- config-struct.yaml | 14 +++++++------- internal/config/types.go | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/config-struct.yaml b/config-struct.yaml index 7791f73..b3f5986 100644 --- a/config-struct.yaml +++ b/config-struct.yaml @@ -26,13 +26,13 @@ certificates: # Описывает список доступных certificates spec: # блок описывающий certificate subject: # блок описывающий принадлежность certificate commonName: string # CommonName is the common name as specified on the DER encoded CSR. If specified, this value must also be present in `dnsNames` or `ipAddresses`. This field must match the corresponding field on the DER encoded CSR. - countries: list of string # Countries to be used on the Certificate. - localities: list of string # Cities to be used on the Certificate. - organizations: list of string # Organizations to be used on the Certificate. - organizationalUnits: list of string # Organizational Units to be used on the Certificate. - provinces: list of string # State/Provinces to be used on the Certificate. - postalCodes: list of string # Postal codes to be used on the Certificate. - streetAddresses: list of string # Street addresses to be used on the Certificate. + country: list of string # Countries to be used on the Certificate. + localite: list of string # Cities to be used on the Certificate. + organization: list of string # Organizations to be used on the Certificate. + organizationalUnit: list of string # Organizational Units to be used on the Certificate. + province: list of string # State/Provinces to be used on the Certificate. + postalCode: list of string # Postal codes to be used on the Certificate. + streetAddress: list of string # Street addresses to be used on the Certificate. serialNumber: string # Serial number to be used on the Certificate privateKey: # Options to control private keys used for the Certificate. algorithm: string # Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either `RSA`,`Ed25519` or `ECDSA` If `algorithm` is specified and `size` is not provided, key size of 256 will be used for `ECDSA` key algorithm and key size of 2048 will be used for `RSA` key algorithm. key size is ignored when using the `Ed25519` key algorithm. diff --git a/internal/config/types.go b/internal/config/types.go index 4563a74..2c69494 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -86,13 +86,13 @@ type Spec struct { type Subject struct { CommonName string `yaml:"commonName"` - Country []string `yaml:"countries"` - Locality []string `yaml:"localities"` - Organization []string `yaml:"organizations"` - OrganizationalUnit []string `yaml:"organizationalUnits"` - Province []string `yaml:"provinces"` - PostalCode []string `yaml:"postalCodes"` - StreetAddress []string `yaml:"streetAddresses"` + Country []string `yaml:"country"` + Locality []string `yaml:"locality"` + Organization []string `yaml:"organization"` + OrganizationalUnit []string `yaml:"organizationalUnit"` + Province []string `yaml:"province"` + PostalCode []string `yaml:"postalCode"` + StreetAddress []string `yaml:"streetAddress"` SerialNumber string `yaml:"serialNumber"` } From 967770277cfe12a677638adb8070f32743cfd85d Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 5 Sep 2022 09:52:47 +0300 Subject: [PATCH 116/220] update --- config-struct.yaml | 8 ++--- internal/config/types.go | 9 ++--- internal/resource/key.go | 71 ++-------------------------------------- 3 files changed, 7 insertions(+), 81 deletions(-) diff --git a/config-struct.yaml b/config-struct.yaml index b3f5986..df5307c 100644 --- a/config-struct.yaml +++ b/config-struct.yaml @@ -38,7 +38,6 @@ certificates: # Описывает список доступных certificates algorithm: string # Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either `RSA`,`Ed25519` or `ECDSA` If `algorithm` is specified and `size` is not provided, key size of 256 will be used for `ECDSA` key algorithm and key size of 2048 will be used for `RSA` key algorithm. key size is ignored when using the `Ed25519` key algorithm. encoding: string # The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 and PKCS#8, respectively. Defaults to `PKCS1` if not specified. size: integer # Size is the key bit size of the corresponding private key for this certificate. If `algorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified. If `algorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, and will default to `256` if not specified. If `algorithm` is set to `Ed25519`, Size is ignored. No other values are allowed. - usages: list of string # Usages is the set of x509 usages that are requested for the certificate. Defaults to `digital signature` and `key encipherment` if not specified. hostnames: list of string # List of DNSNames that this solver will be used to solve. If specified and a match is found, a dnsNames selector will take precedence over a dnsZones selector. If multiple solvers match with the same dnsNames value, the solver with the most matching labels in matchLabels will be selected. If neither has more matches, the solver defined earlier in the list will be selected. ipAddresses: list of string # IPAddresses is a list of IP addresses that should be included as part of the Order validation process. This field must match the corresponding field on the DER encoded CSR. ttl: string # на какой промежуток времени заказывается сертификат @@ -52,9 +51,6 @@ certificates: # Описывает список доступных certificates keys: # Описывает список доступных keys - name: # Имя key - privateKey: # Options to control private keys used for the Certificate. - algorithm: string # Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either `RSA`,`Ed25519` or `ECDSA` If `algorithm` is specified and `size` is not provided, key size of 256 will be used for `ECDSA` key algorithm and key size of 2048 will be used for `RSA` key algorithm. key size is ignored when using the `Ed25519` key algorithm. - encoding: string # The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 and PKCS#8, respectively. Defaults to `PKCS1` if not specified. - size: integer # Size is the key bit size of the corresponding private key for this certificate. If `algorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified. If `algorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, and will default to `256` if not specified. If `algorithm` is set to `Ed25519`, Size is ignored. No other values are allowed. - public: true # если false генерил локально, true генерил локально и пушил в vault + issuerRef: # IssuerRef references a properly configured ACME-type Issuer which should be used to create this Order. If the Issuer does not exist, processing will be retried. If the Issuer is not an 'ACME' Issuer, an error will be returned and the Order will be marked as failed. + name: string # Имя вызываемого ISSUER hostPath: string # путь, где будет размещен секрет по маске ${hostPathCert}/${keyName} diff --git a/internal/config/types.go b/internal/config/types.go index 2c69494..f4db09d 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -30,11 +30,9 @@ type Certificate struct { } type Key struct { - Name string `yaml:"name"` - IssuerRef IssuerRef `yaml:"issuerRef"` - PrivateKey PrivateKey `yaml:"privateKey"` - Public bool `yaml:"public"` - HostPath string `yaml:"hostPath"` + Name string `yaml:"name"` + IssuerRef IssuerRef `yaml:"issuerRef"` + HostPath string `yaml:"hostPath"` } type IssuerRef struct { @@ -78,7 +76,6 @@ type AppRole struct { type Spec struct { Subject Subject `yaml:"subject"` PrivateKey PrivateKey `yaml:"privateKey"` - Usages []string `yaml:"usages"` Hostnames []string `yaml:"hostnames"` IPAddresses []string `yaml:"ipAddresses"` TTL string `yaml:"ttl"` diff --git a/internal/resource/key.go b/internal/resource/key.go index 95c4f49..6c2c115 100644 --- a/internal/resource/key.go +++ b/internal/resource/key.go @@ -1,12 +1,7 @@ package resource import ( - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "encoding/pem" "fmt" - "strings" "go.uber.org/zap" @@ -14,41 +9,13 @@ import ( ) func (s *resource) checkKey(i config.Key) { - private, public, err := s.readRSA(i) + private, public, err := s.readKey(i) if err != nil { zap.L().Warn( "read rsa", zap.String("name", i.Name), zap.Error(err), ) - private, public, err = s.generateKey(i.PrivateKey) - if err != nil { - zap.L().Error( - "generate rsa", - zap.String("name", i.Name), - zap.Error(err), - ) - return - } - zap.L().Debug("rsa is created", zap.String("name", i.Name)) - - if i.Public { - storedRSA := map[string]interface{}{ - "private": string(private), - "public": string(public), - } - - if err := s.vault.Put(i.Name, storedRSA); err != nil { - zap.L().Error( - "store rsa in kv", - zap.String("name", i.Name), - zap.Error(err), - ) - return - } - zap.L().Debug("rsa is saved in kv", zap.String("name", i.Name)) - } - } else { zap.L().Debug("rsa is read", zap.String("name", i.Name)) } @@ -65,7 +32,7 @@ func (s *resource) checkKey(i config.Key) { zap.L().Debug("rsa is stored", zap.String("name", i.Name)) } -func (s *resource) readRSA(i config.Key) (private []byte, public []byte, err error) { +func (s *resource) readKey(i config.Key) (private []byte, public []byte, err error) { storedRSA, err := s.vault.Get(i.Name) if err != nil { err = fmt.Errorf("get from vault_kv : %w", err) @@ -75,37 +42,3 @@ func (s *resource) readRSA(i config.Key) (private []byte, public []byte, err err private, public = []byte(storedRSA["private"].(string)), []byte(storedRSA["public"].(string)) return } - -func (s *resource) generateKey(info config.PrivateKey) (private []byte, public []byte, err error) { - if strings.ToLower(info.Algorithm) != "rsa" { - err = fmt.Errorf("the algorithm %s is not supported", info.Algorithm) - return - } - return s.generateRSA(info.Size) -} - -func (s *resource) generateRSA(size int) (private []byte, public []byte, err error) { - privKey, err := rsa.GenerateKey(rand.Reader, size) - if err != nil { - return - } - - private = pem.EncodeToMemory( - &pem.Block{ - Type: "RSA PRIVATE KEY", - Bytes: x509.MarshalPKCS1PrivateKey(privKey), - }, - ) - - publicKeyBytes, err := x509.MarshalPKIXPublicKey(&privKey.PublicKey) - if err != nil { - return - } - public = pem.EncodeToMemory( - &pem.Block{ - Type: "PUBLIC KEY", - Bytes: publicKeyBytes, - }, - ) - return -} From 27143e9506c984b5b1cd3246fb95920d8dbb6522 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 5 Sep 2022 10:49:15 +0300 Subject: [PATCH 117/220] update --- config-struct.yaml | 5 +++- internal/config/types.go | 16 ++++++++---- internal/resource/utils.go | 50 ++++++++++++++++++++++++++++++++++---- 3 files changed, 60 insertions(+), 11 deletions(-) diff --git a/config-struct.yaml b/config-struct.yaml index df5307c..1688f85 100644 --- a/config-struct.yaml +++ b/config-struct.yaml @@ -39,7 +39,10 @@ certificates: # Описывает список доступных certificates encoding: string # The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 and PKCS#8, respectively. Defaults to `PKCS1` if not specified. size: integer # Size is the key bit size of the corresponding private key for this certificate. If `algorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified. If `algorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, and will default to `256` if not specified. If `algorithm` is set to `Ed25519`, Size is ignored. No other values are allowed. hostnames: list of string # List of DNSNames that this solver will be used to solve. If specified and a match is found, a dnsNames selector will take precedence over a dnsZones selector. If multiple solvers match with the same dnsNames value, the solver with the most matching labels in matchLabels will be selected. If neither has more matches, the solver defined earlier in the list will be selected. - ipAddresses: list of string # IPAddresses is a list of IP addresses that should be included as part of the Order validation process. This field must match the corresponding field on the DER encoded CSR. + ipAddresses: + static: list of string + interfaces: list of string + dnsLookup: list of string ttl: string # на какой промежуток времени заказывается сертификат vault: role: string # альтернатива блоку csr[*].role diff --git a/internal/config/types.go b/internal/config/types.go index f4db09d..e6a507b 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -74,11 +74,11 @@ type AppRole struct { } type Spec struct { - Subject Subject `yaml:"subject"` - PrivateKey PrivateKey `yaml:"privateKey"` - Hostnames []string `yaml:"hostnames"` - IPAddresses []string `yaml:"ipAddresses"` - TTL string `yaml:"ttl"` + Subject Subject `yaml:"subject"` + PrivateKey PrivateKey `yaml:"privateKey"` + Hostnames []string `yaml:"hostnames"` + IPAddresses IPAddresses `yaml:"ipAddresses"` + TTL string `yaml:"ttl"` } type Subject struct { @@ -99,6 +99,12 @@ type PrivateKey struct { Size int `yaml:"size"` } +type IPAddresses struct { + Static []string `yaml:"static"` + Interfaces []string `yaml:"interfaces"` + DNSLookup []string `yaml:"dnsLookup"` +} + type CertVault struct { Role string `yaml:"role"` Path string `yaml:"path"` diff --git a/internal/resource/utils.go b/internal/resource/utils.go index 5c0453f..fedd868 100644 --- a/internal/resource/utils.go +++ b/internal/resource/utils.go @@ -102,13 +102,44 @@ func createCSR(spec config.Spec) (crt, key []byte) { } -func getIPAddresses(ips []string) []net.IP { - ipAddresses := make([]net.IP, 0, len(ips)) +func getIPAddresses(cfg config.IPAddresses) []net.IP { + ipAddresses := make(map[string]net.IP) - for _, ip := range ips { - ipAddresses = append(ipAddresses, net.IP(ip)) + for _, ip := range cfg.Static { + ipAddresses[ip] = net.IP(ip) } - return ipAddresses + + ifaces, _ := net.Interfaces() + // TODO: handle err + for _, i := range ifaces { + if inSlice(i.Name, cfg.Interfaces) { + addrs, _ := i.Addrs() + // TODO: handle err + for _, addr := range addrs { + var ip net.IP + switch v := addr.(type) { + case *net.IPNet: + ip = v.IP + case *net.IPAddr: + ip = v.IP + } + ipAddresses[ip.String()] = ip + } + } + } + + for _, h := range cfg.DNSLookup { + ips, _ := net.LookupIP(h) + for _, ip := range ips { + ipAddresses[ip.String()] = ip + } + } + + r := make([]net.IP, len(ipAddresses)) + for _, ip := range ipAddresses { + r = append(r, ip) + } + return r } func getURIs(hostnames []string) []*url.URL { @@ -121,3 +152,12 @@ func getURIs(hostnames []string) []*url.URL { } return urls } + +func inSlice(str string, sl []string) bool { + for _, s := range sl { + if str == s { + return true + } + } + return false +} From bac401bc7130e55decbbfbc9111c1f79b11431d2 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 5 Sep 2022 14:45:26 +0300 Subject: [PATCH 118/220] update --- internal/resource/certificate.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/resource/certificate.go b/internal/resource/certificate.go index d2b0f97..0957ebd 100644 --- a/internal/resource/certificate.go +++ b/internal/resource/certificate.go @@ -57,8 +57,9 @@ func (s *resource) generateCertificate(cfg config.Certificate) ([]byte, []byte, csr, key := createCSR(cfg.Spec) certData := map[string]interface{}{ - "csr": string(csr), - "ttl": cfg.Spec.TTL, + "csr": string(csr), + "ip_sans": strings.Join(cfg.Spec.IPAddresses.Static, ","), + "ttl": cfg.Spec.TTL, } fmt.Println(string(csr)) path := path.Join(cfg.Vault.Path, "sign", cfg.Vault.Role) From 9f1d1215caab33b4c43a2fe3eee7ccbe77d01e46 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 5 Sep 2022 16:41:29 +0300 Subject: [PATCH 119/220] add debug info --- internal/resource/certificate.go | 7 +++---- internal/resource/utils.go | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/resource/certificate.go b/internal/resource/certificate.go index 0957ebd..9b076a3 100644 --- a/internal/resource/certificate.go +++ b/internal/resource/certificate.go @@ -57,11 +57,10 @@ func (s *resource) generateCertificate(cfg config.Certificate) ([]byte, []byte, csr, key := createCSR(cfg.Spec) certData := map[string]interface{}{ - "csr": string(csr), - "ip_sans": strings.Join(cfg.Spec.IPAddresses.Static, ","), - "ttl": cfg.Spec.TTL, + "csr": string(csr), + "ttl": cfg.Spec.TTL, } - fmt.Println(string(csr)) + path := path.Join(cfg.Vault.Path, "sign", cfg.Vault.Role) cert, err := s.vault.Write(path, certData) if err != nil { diff --git a/internal/resource/utils.go b/internal/resource/utils.go index fedd868..760991e 100644 --- a/internal/resource/utils.go +++ b/internal/resource/utils.go @@ -137,6 +137,7 @@ func getIPAddresses(cfg config.IPAddresses) []net.IP { r := make([]net.IP, len(ipAddresses)) for _, ip := range ipAddresses { + fmt.Println("ip", ip.String()) r = append(r, ip) } return r From 8f0674c291d70150773389bec5109191d6848140 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 5 Sep 2022 16:45:36 +0300 Subject: [PATCH 120/220] add debug info --- internal/resource/utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/resource/utils.go b/internal/resource/utils.go index 760991e..1a776ca 100644 --- a/internal/resource/utils.go +++ b/internal/resource/utils.go @@ -137,7 +137,7 @@ func getIPAddresses(cfg config.IPAddresses) []net.IP { r := make([]net.IP, len(ipAddresses)) for _, ip := range ipAddresses { - fmt.Println("ip", ip.String()) + fmt.Printf("ip %s\n", ip.String()) r = append(r, ip) } return r From b47811ee753c662c89e9e2d3ac02efcdb85890f6 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 5 Sep 2022 16:58:31 +0300 Subject: [PATCH 121/220] add ipv4 --- internal/resource/utils.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/internal/resource/utils.go b/internal/resource/utils.go index 1a776ca..a289e63 100644 --- a/internal/resource/utils.go +++ b/internal/resource/utils.go @@ -123,7 +123,11 @@ func getIPAddresses(cfg config.IPAddresses) []net.IP { case *net.IPAddr: ip = v.IP } - ipAddresses[ip.String()] = ip + + if ip.To4() != nil { + fmt.Printf("ip Interfaces %s\n", ip.String()) + ipAddresses[ip.String()] = ip + } } } } @@ -131,7 +135,10 @@ func getIPAddresses(cfg config.IPAddresses) []net.IP { for _, h := range cfg.DNSLookup { ips, _ := net.LookupIP(h) for _, ip := range ips { - ipAddresses[ip.String()] = ip + if ip.To4() != nil { + fmt.Printf("ip DNSLookup %s\n", ip.String()) + ipAddresses[ip.String()] = ip + } } } From 929e89deec4fa5248111d9e83767309e7827ef3d Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 5 Sep 2022 17:19:21 +0300 Subject: [PATCH 122/220] add ipv4 --- internal/resource/utils.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/internal/resource/utils.go b/internal/resource/utils.go index a289e63..fa322ac 100644 --- a/internal/resource/utils.go +++ b/internal/resource/utils.go @@ -106,7 +106,11 @@ func getIPAddresses(cfg config.IPAddresses) []net.IP { ipAddresses := make(map[string]net.IP) for _, ip := range cfg.Static { - ipAddresses[ip] = net.IP(ip) + ip := net.IP(ip) + if ip.To4() != nil { + fmt.Printf("ip DNSLookup %s\n", ip.String()) + ipAddresses[ip.String()] = ip + } } ifaces, _ := net.Interfaces() From 6ad2bd6233a99c75c0d13d48aa5c6940b2ab0b5f Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 5 Sep 2022 17:19:43 +0300 Subject: [PATCH 123/220] add ipv4 --- internal/resource/utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/resource/utils.go b/internal/resource/utils.go index fa322ac..70d831b 100644 --- a/internal/resource/utils.go +++ b/internal/resource/utils.go @@ -108,7 +108,7 @@ func getIPAddresses(cfg config.IPAddresses) []net.IP { for _, ip := range cfg.Static { ip := net.IP(ip) if ip.To4() != nil { - fmt.Printf("ip DNSLookup %s\n", ip.String()) + fmt.Printf("ip static %s\n", ip.String()) ipAddresses[ip.String()] = ip } } From 150b48b94f5aca2b95ee105e73e0be779ab90a76 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 5 Sep 2022 17:27:19 +0300 Subject: [PATCH 124/220] fix --- internal/resource/utils.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/internal/resource/utils.go b/internal/resource/utils.go index 70d831b..f999b96 100644 --- a/internal/resource/utils.go +++ b/internal/resource/utils.go @@ -108,7 +108,6 @@ func getIPAddresses(cfg config.IPAddresses) []net.IP { for _, ip := range cfg.Static { ip := net.IP(ip) if ip.To4() != nil { - fmt.Printf("ip static %s\n", ip.String()) ipAddresses[ip.String()] = ip } } @@ -129,7 +128,6 @@ func getIPAddresses(cfg config.IPAddresses) []net.IP { } if ip.To4() != nil { - fmt.Printf("ip Interfaces %s\n", ip.String()) ipAddresses[ip.String()] = ip } } @@ -140,15 +138,13 @@ func getIPAddresses(cfg config.IPAddresses) []net.IP { ips, _ := net.LookupIP(h) for _, ip := range ips { if ip.To4() != nil { - fmt.Printf("ip DNSLookup %s\n", ip.String()) ipAddresses[ip.String()] = ip } } } - r := make([]net.IP, len(ipAddresses)) + r := make([]net.IP, 0, len(ipAddresses)) for _, ip := range ipAddresses { - fmt.Printf("ip %s\n", ip.String()) r = append(r, ip) } return r From 78aee7da3281572d7ca310dc0eb4beed213ba256 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 5 Sep 2022 17:55:31 +0300 Subject: [PATCH 125/220] update --- internal/resource/utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/resource/utils.go b/internal/resource/utils.go index f999b96..364fc3c 100644 --- a/internal/resource/utils.go +++ b/internal/resource/utils.go @@ -81,7 +81,7 @@ func createCSR(spec config.Spec) (crt, key []byte) { SerialNumber: spec.Subject.SerialNumber, }, IPAddresses: getIPAddresses(spec.IPAddresses), - URIs: getURIs(spec.Hostnames), + DNSNames: spec.Hostnames, SignatureAlgorithm: x509.SHA256WithRSA, } From 11ec1032b10af1d61e15fc4f2e6d213ebebcdaa8 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 5 Sep 2022 18:06:01 +0300 Subject: [PATCH 126/220] update --- config-struct.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/config-struct.yaml b/config-struct.yaml index 1688f85..79e10c7 100644 --- a/config-struct.yaml +++ b/config-struct.yaml @@ -13,6 +13,8 @@ issuers: # Описывает список доступных issuers path: string # rename $approle_path roleIDLocalPath: string # rename $local_path_to_role_id secretIDLocalPath: string # rename $local_path_to_secret_id + kv: + path: string timeout: string # строка формата "1s", таймаут для любого обращения к issuer certificates: # Описывает список доступных certificates @@ -39,7 +41,7 @@ certificates: # Описывает список доступных certificates encoding: string # The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 and PKCS#8, respectively. Defaults to `PKCS1` if not specified. size: integer # Size is the key bit size of the corresponding private key for this certificate. If `algorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified. If `algorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, and will default to `256` if not specified. If `algorithm` is set to `Ed25519`, Size is ignored. No other values are allowed. hostnames: list of string # List of DNSNames that this solver will be used to solve. If specified and a match is found, a dnsNames selector will take precedence over a dnsZones selector. If multiple solvers match with the same dnsNames value, the solver with the most matching labels in matchLabels will be selected. If neither has more matches, the solver defined earlier in the list will be selected. - ipAddresses: + ipAddresses: static: list of string interfaces: list of string dnsLookup: list of string From d74e8f236dec4b346d4d1bcba2e1f064fa78a605 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 5 Sep 2022 18:18:57 +0300 Subject: [PATCH 127/220] up --- internal/resource/utils.go | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/internal/resource/utils.go b/internal/resource/utils.go index 364fc3c..0eb3fd0 100644 --- a/internal/resource/utils.go +++ b/internal/resource/utils.go @@ -8,9 +8,9 @@ import ( "encoding/pem" "fmt" "net" - "net/url" "os" "path" + "regexp" "github.com/fraima/key-keeper/internal/config" ) @@ -106,10 +106,7 @@ func getIPAddresses(cfg config.IPAddresses) []net.IP { ipAddresses := make(map[string]net.IP) for _, ip := range cfg.Static { - ip := net.IP(ip) - if ip.To4() != nil { - ipAddresses[ip.String()] = ip - } + ipAddresses[ip] = net.IP(ip) } ifaces, _ := net.Interfaces() @@ -150,20 +147,9 @@ func getIPAddresses(cfg config.IPAddresses) []net.IP { return r } -func getURIs(hostnames []string) []*url.URL { - urls := make([]*url.URL, 0, len(hostnames)) - - for _, hostname := range hostnames { - // TODO: error handler - url, _ := url.Parse(hostname) - urls = append(urls, url) - } - return urls -} - func inSlice(str string, sl []string) bool { for _, s := range sl { - if str == s { + if regexp.MustCompile(s).Match([]byte(s)) { return true } } From 1d22dc17dc719f46b8a7b33d1360753085e56fc6 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Mon, 5 Sep 2022 18:26:20 +0300 Subject: [PATCH 128/220] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D1=88=D0=B0?= =?UTF-8?q?=D0=B1=D0=BB=D0=BE=D0=BD=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test.yaml | 492 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 252 insertions(+), 240 deletions(-) diff --git a/test.yaml b/test.yaml index af2327d..024fce1 100644 --- a/test.yaml +++ b/test.yaml @@ -241,51 +241,51 @@ issuers: timeout: 15s certificates: - - name: front-proxy-ca - issuerRef: - name: front-proxy-ca - isCa: true - ca: - exportedKey: false - generate: false - vault: - role: "" - path: "clusters/cluster-1/pki/front-proxy" - rootCAPath: "clusters/cluster-1/pki/root" - hostPath: /tmp/keep/certs/front-proxy-ca - renewBefore: 2160h + # - name: front-proxy-ca + # issuerRef: + # name: front-proxy-ca + # isCa: true + # ca: + # exportedKey: false + # generate: false + # vault: + # role: "" + # path: "clusters/cluster-1/pki/front-proxy" + # rootCAPath: "clusters/cluster-1/pki/root" + # hostPath: /tmp/keep/certs/front-proxy-ca + # renewBefore: 2160h - - name: front-proxy-client - issuerRef: - name: front-proxy-client - vault: - role: "front-proxy-client" - path: "clusters/cluster-1/pki/front-proxy" - spec: - commonName: front-proxy-client - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - client auth - ttl: 100h - renewBefore: 360h - hostPath: "/tmp/keep/certs/front-proxy-client" + # - name: front-proxy-client + # issuerRef: + # name: front-proxy-client + # vault: + # role: "front-proxy-client" + # path: "clusters/cluster-1/pki/front-proxy" + # spec: + # commonName: front-proxy-client + # privateKey: + # algorithm: RSA + # encoding: PKCS1 + # size: 4096 + # usages: + # - client auth + # ttl: 100h + # renewBefore: 360h + # hostPath: "/tmp/keep/certs/front-proxy-client" - - name: kubernetes-ca - issuerRef: - name: kubernetes-ca - isCa: true - ca: - exportedKey: false - generate: false - vault: - role: "" - path: "clusters/cluster-1/pki/kubernetes" - rootCAPath: "clusters/cluster-1/pki/root" - hostPath: /tmp/keep/certs/kubernetes-ca - renewBefore: 2160h + # - name: kubernetes-ca + # issuerRef: + # name: kubernetes-ca + # isCa: true + # ca: + # exportedKey: false + # generate: false + # vault: + # role: "" + # path: "clusters/cluster-1/pki/kubernetes" + # rootCAPath: "clusters/cluster-1/pki/root" + # hostPath: /tmp/keep/certs/kubernetes-ca + # renewBefore: 2160h - name: kube-apiserver-server issuerRef: @@ -294,7 +294,8 @@ certificates: role: "kube-apiserver" path: "clusters/cluster-1/pki/kubernetes" spec: - commonName: custom:kube-apiserver-server + subject: + commonName: custom:kube-apiserver-server privateKey: algorithm: RSA encoding: PKCS1 @@ -309,8 +310,15 @@ certificates: - "kubernetes.default.svc.cluster" - "kubernetes.default.svc.cluster.local" - "api.cluster-1.dobry-kot.ru" - ipAddresses: - - 127.0.0.1 + ipAddresses: + static: + - 127.0.0.1 + - 10.10.10.0 + interfaces: + - wlp0s20f3 + dnsLookup: + - dk-HP-ProBook-440-G6 + ttl: 100h hostPath: "/tmp/keep/certs/kube-apiserver-server" @@ -321,7 +329,6 @@ certificates: role: "kube-apiserver-kubelet-client" path: "clusters/cluster-1/pki/kubernetes" spec: - commonName: custom:kube-apiserver-kubelet-client privateKey: algorithm: RSA encoding: PKCS1 @@ -329,211 +336,216 @@ certificates: usages: - client auth subject: + commonName: custom:kube-apiserver-kubelet-client organizationalUnits: - system:masters ttl: 100h renewBefore: 360h hostPath: "/tmp/keep/certs/kube-apiserver-kubelet-client" - - name: kube-controller-manager-client - issuerRef: - name: kube-controller-manager-client - vault: - role: "kube-controller-manager-client" - path: "clusters/cluster-1/pki/kubernetes" - spec: - commonName: custom:kube-controller-manager-client - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - client auth - ttl: 100h - renewBefore: 360h - hostPath: "/tmp/keep/certs/kube-controller-manager-client" +# - name: kube-controller-manager-client +# issuerRef: +# name: kube-controller-manager-client +# vault: +# role: "kube-controller-manager-client" +# path: "clusters/cluster-1/pki/kubernetes" +# spec: +# commonName: custom:kube-controller-manager-client +# privateKey: +# algorithm: RSA +# encoding: PKCS1 +# size: 4096 +# usages: +# - client auth +# ttl: 100h +# renewBefore: 360h +# hostPath: "/tmp/keep/certs/kube-controller-manager-client" - - name: kube-controller-manager-server - issuerRef: - name: kube-controller-manager-server - vault: - role: "kube-controller-manager-server" - path: "clusters/cluster-1/pki/kubernetes" - spec: - commonName: custom:kube-controller-manager-server - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - server auth - hostnames: - - "localhost" - - "kube-controller-manager.default" - - "kube-controller-manager.default.svc" - - "kube-controller-manager.default.svc.cluster" - - "kube-controller-manager.default.svc.cluster.local" - ipAddresses: - - "127.0.0.1" - - "127.0.1.1" - - "127.0.1.6" - ttl: 100h - hostPath: "/tmp/keep/certs/kube-controller-manager-server" +# - name: kube-controller-manager-server +# issuerRef: +# name: kube-controller-manager-server +# vault: +# role: "kube-controller-manager-server" +# path: "clusters/cluster-1/pki/kubernetes" +# spec: +# commonName: custom:kube-controller-manager-server +# privateKey: +# algorithm: RSA +# encoding: PKCS1 +# size: 4096 +# usages: +# - server auth +# hostnames: +# - "localhost" +# - "kube-controller-manager.default" +# - "kube-controller-manager.default.svc" +# - "kube-controller-manager.default.svc.cluster" +# - "kube-controller-manager.default.svc.cluster.local" +# ipAddresses: +# static: +# - 127.0.0.1 +# interfaces: +# - wlp0s20f3 +# dnsLookup: +# - yandex.ru +# ttl: 100h +# hostPath: "/tmp/keep/certs/kube-controller-manager-server" - - name: kube-scheduler-server - issuerRef: - name: kube-scheduler-server - vault: - role: "kube-scheduler-server" - path: "clusters/cluster-1/pki/kubernetes" - spec: - commonName: custom:kube-scheduler-server - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - server auth - hostnames: - - "localhost" - - "kube-scheduler.default" - - "kube-scheduler.default.svc" - - "kube-scheduler.default.svc.cluster" - - "kube-scheduler.default.svc.cluster.local" - ipAddresses: - - "127.0.0.1" - - "127.0.1.1" - - "127.0.1.6" - ttl: 100h - hostPath: "/tmp/keep/certs/kube-scheduler-server" +# - name: kube-scheduler-server +# issuerRef: +# name: kube-scheduler-server +# vault: +# role: "kube-scheduler-server" +# path: "clusters/cluster-1/pki/kubernetes" +# spec: +# commonName: custom:kube-scheduler-server +# privateKey: +# algorithm: RSA +# encoding: PKCS1 +# size: 4096 +# usages: +# - server auth +# hostnames: +# - "localhost" +# - "kube-scheduler.default" +# - "kube-scheduler.default.svc" +# - "kube-scheduler.default.svc.cluster" +# - "kube-scheduler.default.svc.cluster.local" +# ipAddresses: +# static: +# - 127.0.0.1 +# ttl: 100h +# hostPath: "/tmp/keep/certs/kube-scheduler-server" - - name: kube-scheduler-client - issuerRef: - name: kube-scheduler-client - vault: - role: "kube-scheduler-client" - path: "clusters/cluster-1/pki/kubernetes" - spec: - commonName: system:kube-scheduler - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - client auth - ttl: 100h - renewBefore: 360h - hostPath: "/tmp/keep/certs/kube-scheduler-client" +# - name: kube-scheduler-client +# issuerRef: +# name: kube-scheduler-client +# vault: +# role: "kube-scheduler-client" +# path: "clusters/cluster-1/pki/kubernetes" +# spec: +# commonName: system:kube-scheduler +# privateKey: +# algorithm: RSA +# encoding: PKCS1 +# size: 4096 +# usages: +# - client auth +# ttl: 100h +# renewBefore: 360h +# hostPath: "/tmp/keep/certs/kube-scheduler-client" - - name: kubelet-client - issuerRef: - name: kubelet-client - vault: - role: "kubelet-client" - path: "clusters/cluster-1/pki/kubernetes" - spec: - commonName: system:node:${instance_name} - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - subject: - organizations: - - system:nodes - usages: - - client auth - ttl: 100h - renewBefore: 360h - hostPath: "/tmp/keep/certs/kubelet-client" +# - name: kubelet-client +# issuerRef: +# name: kubelet-client +# vault: +# role: "kubelet-client" +# path: "clusters/cluster-1/pki/kubernetes" +# spec: +# commonName: system:node:${instance_name} +# privateKey: +# algorithm: RSA +# encoding: PKCS1 +# size: 4096 +# subject: +# organizations: +# - system:nodes +# usages: +# - client auth +# ttl: 100h +# renewBefore: 360h +# hostPath: "/tmp/keep/certs/kubelet-client" - - name: etcd-ca - issuerRef: - name: etcd-ca - isCa: true - ca: - exportedKey: false - generate: false - vault: - role: "" - path: "clusters/cluster-1/pki/etcd" - rootCAPath: "clusters/cluster-1/pki/root" - hostPath: /tmp/keep/certs/etcd-ca - renewBefore: 2160h +# - name: etcd-ca +# issuerRef: +# name: etcd-ca +# isCa: true +# ca: +# exportedKey: false +# generate: false +# vault: +# role: "" +# path: "clusters/cluster-1/pki/etcd" +# rootCAPath: "clusters/cluster-1/pki/root" +# hostPath: /tmp/keep/certs/etcd-ca +# renewBefore: 2160h - - name: etcd-peer - issuerRef: - name: etcd-peer - vault: - role: "etcd-peer" - path: "clusters/cluster-1/pki/etcd" - spec: - commonName: custom:etcd-peer - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - server auth - - client auth - hostnames: - - "localhost" - - "${ instance_name }.${base_domain}" - ipAddresses: - - "127.0.0.1" - - "127.0.1.1" - - "127.0.1.6" - ttl: 100h - hostPath: "/tmp/keep/certs/etcd-peer" +# - name: etcd-peer +# issuerRef: +# name: etcd-peer +# vault: +# role: "etcd-peer" +# path: "clusters/cluster-1/pki/etcd" +# spec: +# commonName: custom:etcd-peer +# privateKey: +# algorithm: RSA +# encoding: PKCS1 +# size: 4096 +# usages: +# - server auth +# - client auth +# hostnames: +# - "localhost" +# - "${ instance_name }.${base_domain}" +# ipAddresses: +# static: +# - 127.0.0.1 +# dnsLookup: +# - "${ instance_name }.${base_domain}" +# ttl: 100h +# hostPath: "/tmp/keep/certs/etcd-peer" - - name: etcd-server - issuerRef: - name: etcd-server - vault: - role: "etcd-server" - path: "clusters/cluster-1/pki/etcd" - spec: - commonName: custom:etcd-server - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - server auth - hostnames: - - "localhost" - - "${ instance_name }.${base_domain}" - ipAddresses: - - "127.0.0.1" - - "127.0.1.1" - - "127.0.1.6" - ttl: 100h - hostPath: "/tmp/keep/certs/etcd-server" +# - name: etcd-server +# issuerRef: +# name: etcd-server +# vault: +# role: "etcd-server" +# path: "clusters/cluster-1/pki/etcd" +# spec: +# commonName: custom:etcd-server +# privateKey: +# algorithm: RSA +# encoding: PKCS1 +# size: 4096 +# usages: +# - server auth +# hostnames: +# - "localhost" +# - "${ instance_name }.${base_domain}" +# ipAddresses: +# static: +# - 127.0.0.1 +# dnsLookup: +# - "${ instance_name }.${base_domain}" +# ttl: 100h +# hostPath: "/tmp/keep/certs/etcd-server" - - name: etcd-kube-apiserver-client - issuerRef: - name: etcd-client - vault: - role: "etcd-client" - path: "clusters/cluster-1/pki/etcd" - spec: - commonName: custom:etcd-kube-apiserver-client - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - client auth - ttl: 100h - renewBefore: 360h - hostPath: "/tmp/keep/certs/etcd-kube-apiserver-client" +# - name: etcd-kube-apiserver-client +# issuerRef: +# name: etcd-client +# vault: +# role: "etcd-client" +# path: "clusters/cluster-1/pki/etcd" +# spec: +# commonName: custom:etcd-kube-apiserver-client +# privateKey: +# algorithm: RSA +# encoding: PKCS1 +# size: 4096 +# usages: +# - client auth +# ttl: 100h +# renewBefore: 360h +# hostPath: "/tmp/keep/certs/etcd-kube-apiserver-client" -keys: - - name: kube-sa - host_path: /tmp/keep/certs/kube-sa - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 2048 - public: true - vault: - kv: "clusters/cluster-1/kv" +# # keys: +# # - name: kube-sa +# # host_path: /tmp/keep/certs/kube-sa +# # privateKey: +# # algorithm: RSA +# # encoding: PKCS1 +# # size: 2048 +# # public: true +# # vault: +# # kv: "clusters/cluster-1/kv" From e9e37d8507b4b3ee692b24d4533ee82c777ca3d3 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 5 Sep 2022 19:05:49 +0300 Subject: [PATCH 129/220] fix --- internal/resource/utils.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/resource/utils.go b/internal/resource/utils.go index 0eb3fd0..599ead1 100644 --- a/internal/resource/utils.go +++ b/internal/resource/utils.go @@ -103,10 +103,10 @@ func createCSR(spec config.Spec) (crt, key []byte) { } func getIPAddresses(cfg config.IPAddresses) []net.IP { - ipAddresses := make(map[string]net.IP) + ipAddresses := make(map[string]struct{}) for _, ip := range cfg.Static { - ipAddresses[ip] = net.IP(ip) + ipAddresses[ip] = struct{}{} } ifaces, _ := net.Interfaces() @@ -125,7 +125,7 @@ func getIPAddresses(cfg config.IPAddresses) []net.IP { } if ip.To4() != nil { - ipAddresses[ip.String()] = ip + ipAddresses[ip.String()] = struct{}{} } } } @@ -135,14 +135,14 @@ func getIPAddresses(cfg config.IPAddresses) []net.IP { ips, _ := net.LookupIP(h) for _, ip := range ips { if ip.To4() != nil { - ipAddresses[ip.String()] = ip + ipAddresses[ip.String()] = struct{}{} } } } r := make([]net.IP, 0, len(ipAddresses)) - for _, ip := range ipAddresses { - r = append(r, ip) + for ip := range ipAddresses { + r = append(r, net.IP(ip)) } return r } From 108f34b06cb1200b5ab49ca4565b1ef5558c91ee Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 5 Sep 2022 19:15:13 +0300 Subject: [PATCH 130/220] fix --- internal/resource/utils.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/resource/utils.go b/internal/resource/utils.go index 599ead1..75dec37 100644 --- a/internal/resource/utils.go +++ b/internal/resource/utils.go @@ -142,6 +142,7 @@ func getIPAddresses(cfg config.IPAddresses) []net.IP { r := make([]net.IP, 0, len(ipAddresses)) for ip := range ipAddresses { + fmt.Println(ip) r = append(r, net.IP(ip)) } return r From 883d272b8082ba5800aca6d431dc8cf05a2bd598 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 5 Sep 2022 20:15:09 +0300 Subject: [PATCH 131/220] up --- internal/resource/utils.go | 2 +- test.yaml | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/internal/resource/utils.go b/internal/resource/utils.go index 75dec37..587d355 100644 --- a/internal/resource/utils.go +++ b/internal/resource/utils.go @@ -150,7 +150,7 @@ func getIPAddresses(cfg config.IPAddresses) []net.IP { func inSlice(str string, sl []string) bool { for _, s := range sl { - if regexp.MustCompile(s).Match([]byte(s)) { + if regexp.MustCompile(s).MatchString(str) { return true } } diff --git a/test.yaml b/test.yaml index 024fce1..8ea01bd 100644 --- a/test.yaml +++ b/test.yaml @@ -310,15 +310,15 @@ certificates: - "kubernetes.default.svc.cluster" - "kubernetes.default.svc.cluster.local" - "api.cluster-1.dobry-kot.ru" - ipAddresses: + ipAddresses: static: - 127.0.0.1 - 10.10.10.0 interfaces: - - wlp0s20f3 + - lo dnsLookup: - dk-HP-ProBook-440-G6 - + ttl: 100h hostPath: "/tmp/keep/certs/kube-apiserver-server" @@ -342,7 +342,6 @@ certificates: ttl: 100h renewBefore: 360h hostPath: "/tmp/keep/certs/kube-apiserver-kubelet-client" - # - name: kube-controller-manager-client # issuerRef: # name: kube-controller-manager-client @@ -381,7 +380,7 @@ certificates: # - "kube-controller-manager.default.svc" # - "kube-controller-manager.default.svc.cluster" # - "kube-controller-manager.default.svc.cluster.local" -# ipAddresses: +# ipAddresses: # static: # - 127.0.0.1 # interfaces: @@ -411,7 +410,7 @@ certificates: # - "kube-scheduler.default.svc" # - "kube-scheduler.default.svc.cluster" # - "kube-scheduler.default.svc.cluster.local" -# ipAddresses: +# ipAddresses: # static: # - 127.0.0.1 # ttl: 100h @@ -488,7 +487,7 @@ certificates: # hostnames: # - "localhost" # - "${ instance_name }.${base_domain}" -# ipAddresses: +# ipAddresses: # static: # - 127.0.0.1 # dnsLookup: @@ -513,7 +512,7 @@ certificates: # hostnames: # - "localhost" # - "${ instance_name }.${base_domain}" -# ipAddresses: +# ipAddresses: # static: # - 127.0.0.1 # dnsLookup: From cb0a32b652d5b78131b47d11ee054d9cc686c5fc Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Tue, 6 Sep 2022 00:29:43 +0300 Subject: [PATCH 132/220] =?UTF-8?q?=D0=A4=D0=B8=D0=BA=D1=81=D0=B8=D1=82=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B1=D0=BB=D0=B5=D0=BC=D1=83=20ipAddresses?= =?UTF-8?q?=20=D0=B8=20=D0=B8=D0=BC=D0=B5=D0=BD=D1=83=D0=B5=D1=82=20=D1=81?= =?UTF-8?q?=D0=BE=D0=B7=D0=B4=D0=B0=D0=B2=D0=B0=D0=B5=D0=BC=D1=8B=D0=B5=20?= =?UTF-8?q?=D1=81=D0=B5=D1=80=D1=82=D0=B8=D1=84=D0=B8=D0=BA=D0=B0=D1=82?= =?UTF-8?q?=D1=8B=20=D1=87=D0=B5=D1=80=D0=B5=D0=B7=20=D0=B8=D0=BC=D1=8F=20?= =?UTF-8?q?issuer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/resource/ca-certificate.go | 2 +- internal/resource/certificate.go | 4 +- internal/resource/utils.go | 26 +- test.yaml | 494 ++++++++++++++-------------- 4 files changed, 267 insertions(+), 259 deletions(-) diff --git a/internal/resource/ca-certificate.go b/internal/resource/ca-certificate.go index 2c96e1d..c3e74a4 100644 --- a/internal/resource/ca-certificate.go +++ b/internal/resource/ca-certificate.go @@ -19,7 +19,7 @@ func (s *resource) checkCA(cert config.Certificate) { ) defer func() { - if err := s.storeKeyPair(cert.HostPath, crt, key); err != nil { + if err := s.storeKeyPair(cert.HostPath, cert.Name, crt, key); err != nil { zap.L().Error( "stored intermediate-ca", zap.Error(err), diff --git a/internal/resource/certificate.go b/internal/resource/certificate.go index 9b076a3..f96ef6d 100644 --- a/internal/resource/certificate.go +++ b/internal/resource/certificate.go @@ -14,7 +14,7 @@ import ( ) func (s *resource) checkCertificate(cfg config.Certificate) { - cert, err := s.readCertificate(cfg.HostPath) + cert, err := s.readCertificate(cfg.HostPath, cfg.Name) if cert != nil && time.Until(cert.NotAfter) > cfg.RenewBefore { return } @@ -31,7 +31,7 @@ func (s *resource) checkCertificate(cfg config.Certificate) { ) } - if err = s.storeKeyPair(cfg.HostPath, crt, key); err != nil { + if err = s.storeKeyPair(cfg.HostPath, cfg.Name, crt, key); err != nil { zap.L().Error( "store csr", zap.String("name", cfg.Name), diff --git a/internal/resource/utils.go b/internal/resource/utils.go index 587d355..e5bcb2b 100644 --- a/internal/resource/utils.go +++ b/internal/resource/utils.go @@ -26,23 +26,23 @@ func (s *resource) storeKey(path string, privare, public []byte) error { return nil } -func (s *resource) storeKeyPair(path string, crt, key []byte) error { +func (s *resource) storeKeyPair(path string, name string, crt, key []byte) error { if crt != nil { - if err := os.WriteFile(path+".pem", crt, 0644); err != nil { + if err := os.WriteFile(path+"/"+name+".pem", crt, 0644); err != nil { return fmt.Errorf("failed to save certificate with path %s: %w", path, err) } } if key != nil { - if err := os.WriteFile(path+"-key.pem", key, 0600); err != nil { + if err := os.WriteFile(path+"/"+name+"-key.pem", key, 0600); err != nil { return fmt.Errorf("failed to save key file: %w", err) } } return nil } -func (s *resource) readCertificate(path string) (*x509.Certificate, error) { - crt, err := os.ReadFile(path + ".pem") +func (s *resource) readCertificate(path string, name string) (*x509.Certificate, error) { + crt, err := os.ReadFile(path + "/" + name + ".pem") if err != nil { return nil, err } @@ -103,10 +103,13 @@ func createCSR(spec config.Spec) (crt, key []byte) { } func getIPAddresses(cfg config.IPAddresses) []net.IP { - ipAddresses := make(map[string]struct{}) + ipAddresses := make(map[string]net.IP) for _, ip := range cfg.Static { - ipAddresses[ip] = struct{}{} + ip := net.IP(ip) + if ip.To4() != nil { + ipAddresses[ip.String()] = ip + } } ifaces, _ := net.Interfaces() @@ -125,7 +128,7 @@ func getIPAddresses(cfg config.IPAddresses) []net.IP { } if ip.To4() != nil { - ipAddresses[ip.String()] = struct{}{} + ipAddresses[ip.String()] = ip } } } @@ -135,15 +138,14 @@ func getIPAddresses(cfg config.IPAddresses) []net.IP { ips, _ := net.LookupIP(h) for _, ip := range ips { if ip.To4() != nil { - ipAddresses[ip.String()] = struct{}{} + ipAddresses[ip.String()] = ip } } } r := make([]net.IP, 0, len(ipAddresses)) - for ip := range ipAddresses { - fmt.Println(ip) - r = append(r, net.IP(ip)) + for _, ip := range ipAddresses { + r = append(r, ip) } return r } diff --git a/test.yaml b/test.yaml index 8ea01bd..c737243 100644 --- a/test.yaml +++ b/test.yaml @@ -241,51 +241,50 @@ issuers: timeout: 15s certificates: - # - name: front-proxy-ca - # issuerRef: - # name: front-proxy-ca - # isCa: true - # ca: - # exportedKey: false - # generate: false - # vault: - # role: "" - # path: "clusters/cluster-1/pki/front-proxy" - # rootCAPath: "clusters/cluster-1/pki/root" - # hostPath: /tmp/keep/certs/front-proxy-ca - # renewBefore: 2160h + - name: front-proxy-ca + issuerRef: + name: front-proxy-ca + isCa: true + ca: + exportedKey: false + generate: false + vault: + role: "" + path: "clusters/cluster-1/pki/front-proxy" + rootCAPath: "clusters/cluster-1/pki/root" + hostPath: /tmp/keep/certs/ - # - name: front-proxy-client - # issuerRef: - # name: front-proxy-client - # vault: - # role: "front-proxy-client" - # path: "clusters/cluster-1/pki/front-proxy" - # spec: - # commonName: front-proxy-client - # privateKey: - # algorithm: RSA - # encoding: PKCS1 - # size: 4096 - # usages: - # - client auth - # ttl: 100h - # renewBefore: 360h - # hostPath: "/tmp/keep/certs/front-proxy-client" + - name: front-proxy-client + issuerRef: + name: front-proxy-client + vault: + role: "front-proxy-client" + path: "clusters/cluster-1/pki/front-proxy" + spec: + subject: + commonName: custom:front-proxy-client + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 4096 + usages: + - client auth + ttl: 100h + renewBefore: 50h + hostPath: "/tmp/keep/certs/" - # - name: kubernetes-ca - # issuerRef: - # name: kubernetes-ca - # isCa: true - # ca: - # exportedKey: false - # generate: false - # vault: - # role: "" - # path: "clusters/cluster-1/pki/kubernetes" - # rootCAPath: "clusters/cluster-1/pki/root" - # hostPath: /tmp/keep/certs/kubernetes-ca - # renewBefore: 2160h + - name: kubernetes-ca + issuerRef: + name: kubernetes-ca + isCa: true + ca: + exportedKey: false + generate: false + vault: + role: "" + path: "clusters/cluster-1/pki/kubernetes" + rootCAPath: "clusters/cluster-1/pki/root" + hostPath: /tmp/keep/certs/ - name: kube-apiserver-server issuerRef: @@ -317,10 +316,10 @@ certificates: interfaces: - lo dnsLookup: - - dk-HP-ProBook-440-G6 + - yandex.ru ttl: 100h - hostPath: "/tmp/keep/certs/kube-apiserver-server" + hostPath: "/tmp/keep/certs/" - name: kube-apiserver-kubelet-client issuerRef: @@ -340,211 +339,218 @@ certificates: organizationalUnits: - system:masters ttl: 100h - renewBefore: 360h - hostPath: "/tmp/keep/certs/kube-apiserver-kubelet-client" -# - name: kube-controller-manager-client -# issuerRef: -# name: kube-controller-manager-client -# vault: -# role: "kube-controller-manager-client" -# path: "clusters/cluster-1/pki/kubernetes" -# spec: -# commonName: custom:kube-controller-manager-client -# privateKey: -# algorithm: RSA -# encoding: PKCS1 -# size: 4096 -# usages: -# - client auth -# ttl: 100h -# renewBefore: 360h -# hostPath: "/tmp/keep/certs/kube-controller-manager-client" + renewBefore: 50h + hostPath: "/tmp/keep/certs/" -# - name: kube-controller-manager-server -# issuerRef: -# name: kube-controller-manager-server -# vault: -# role: "kube-controller-manager-server" -# path: "clusters/cluster-1/pki/kubernetes" -# spec: -# commonName: custom:kube-controller-manager-server -# privateKey: -# algorithm: RSA -# encoding: PKCS1 -# size: 4096 -# usages: -# - server auth -# hostnames: -# - "localhost" -# - "kube-controller-manager.default" -# - "kube-controller-manager.default.svc" -# - "kube-controller-manager.default.svc.cluster" -# - "kube-controller-manager.default.svc.cluster.local" -# ipAddresses: -# static: -# - 127.0.0.1 -# interfaces: -# - wlp0s20f3 -# dnsLookup: -# - yandex.ru -# ttl: 100h -# hostPath: "/tmp/keep/certs/kube-controller-manager-server" + - name: kube-controller-manager-client + issuerRef: + name: kube-controller-manager-client + vault: + role: "kube-controller-manager-client" + path: "clusters/cluster-1/pki/kubernetes" + spec: + subject: + commonName: system:kube-controller-manager + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 4096 + usages: + - client auth + ttl: 100h + renewBefore: 50h + hostPath: "/tmp/keep/certs/" -# - name: kube-scheduler-server -# issuerRef: -# name: kube-scheduler-server -# vault: -# role: "kube-scheduler-server" -# path: "clusters/cluster-1/pki/kubernetes" -# spec: -# commonName: custom:kube-scheduler-server -# privateKey: -# algorithm: RSA -# encoding: PKCS1 -# size: 4096 -# usages: -# - server auth -# hostnames: -# - "localhost" -# - "kube-scheduler.default" -# - "kube-scheduler.default.svc" -# - "kube-scheduler.default.svc.cluster" -# - "kube-scheduler.default.svc.cluster.local" -# ipAddresses: -# static: -# - 127.0.0.1 -# ttl: 100h -# hostPath: "/tmp/keep/certs/kube-scheduler-server" + - name: kube-controller-manager-server + issuerRef: + name: kube-controller-manager-server + vault: + role: "kube-controller-manager-server" + path: "clusters/cluster-1/pki/kubernetes" + spec: + subject: + commonName: system:kube-controller-manager + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 4096 + usages: + - server auth + hostnames: + - "localhost" + - "kube-controller-manager.default" + - "kube-controller-manager.default.svc" + - "kube-controller-manager.default.svc.cluster" + - "kube-controller-manager.default.svc.cluster.local" + ipAddresses: + static: + - 127.0.0.1 + ttl: 100h + renewBefore: 50h + hostPath: "/tmp/keep/certs/" -# - name: kube-scheduler-client -# issuerRef: -# name: kube-scheduler-client -# vault: -# role: "kube-scheduler-client" -# path: "clusters/cluster-1/pki/kubernetes" -# spec: -# commonName: system:kube-scheduler -# privateKey: -# algorithm: RSA -# encoding: PKCS1 -# size: 4096 -# usages: -# - client auth -# ttl: 100h -# renewBefore: 360h -# hostPath: "/tmp/keep/certs/kube-scheduler-client" + - name: kube-scheduler-server + issuerRef: + name: kube-scheduler-server + vault: + role: "kube-scheduler-server" + path: "clusters/cluster-1/pki/kubernetes" + spec: + subject: + commonName: system:kube-scheduler + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 4096 + usages: + - server auth + hostnames: + - "localhost" + - "kube-scheduler.default" + - "kube-scheduler.default.svc" + - "kube-scheduler.default.svc.cluster" + - "kube-scheduler.default.svc.cluster.local" + ipAddresses: + static: + - 127.0.0.1 + ttl: 100h + renewBefore: 50h + hostPath: "/tmp/keep/certs/" -# - name: kubelet-client -# issuerRef: -# name: kubelet-client -# vault: -# role: "kubelet-client" -# path: "clusters/cluster-1/pki/kubernetes" -# spec: -# commonName: system:node:${instance_name} -# privateKey: -# algorithm: RSA -# encoding: PKCS1 -# size: 4096 -# subject: -# organizations: -# - system:nodes -# usages: -# - client auth -# ttl: 100h -# renewBefore: 360h -# hostPath: "/tmp/keep/certs/kubelet-client" + - name: kube-scheduler-client + issuerRef: + name: kube-scheduler-client + vault: + role: "kube-scheduler-client" + path: "clusters/cluster-1/pki/kubernetes" + spec: + subject: + commonName: system:kube-scheduler + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 4096 + usages: + - client auth + ttl: 100h + renewBefore: 50h + hostPath: "/tmp/keep/certs/" -# - name: etcd-ca -# issuerRef: -# name: etcd-ca -# isCa: true -# ca: -# exportedKey: false -# generate: false -# vault: -# role: "" -# path: "clusters/cluster-1/pki/etcd" -# rootCAPath: "clusters/cluster-1/pki/root" -# hostPath: /tmp/keep/certs/etcd-ca -# renewBefore: 2160h + - name: kubelet-client + issuerRef: + name: kubelet-client + vault: + role: "kubelet-client" + path: "clusters/cluster-1/pki/kubernetes" + spec: + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 4096 + subject: + commonName: system:node:${instance_name} + organizations: + - system:nodes + usages: + - client auth + ttl: 100h + renewBefore: 50h + hostPath: "/tmp/keep/certs/" -# - name: etcd-peer -# issuerRef: -# name: etcd-peer -# vault: -# role: "etcd-peer" -# path: "clusters/cluster-1/pki/etcd" -# spec: -# commonName: custom:etcd-peer -# privateKey: -# algorithm: RSA -# encoding: PKCS1 -# size: 4096 -# usages: -# - server auth -# - client auth -# hostnames: -# - "localhost" -# - "${ instance_name }.${base_domain}" -# ipAddresses: -# static: -# - 127.0.0.1 -# dnsLookup: -# - "${ instance_name }.${base_domain}" -# ttl: 100h -# hostPath: "/tmp/keep/certs/etcd-peer" + - name: etcd-ca + issuerRef: + name: etcd-ca + isCa: true + ca: + exportedKey: false + generate: false + vault: + role: "" + path: "clusters/cluster-1/pki/etcd" + rootCAPath: "clusters/cluster-1/pki/root" + hostPath: /tmp/keep/certs/ -# - name: etcd-server -# issuerRef: -# name: etcd-server -# vault: -# role: "etcd-server" -# path: "clusters/cluster-1/pki/etcd" -# spec: -# commonName: custom:etcd-server -# privateKey: -# algorithm: RSA -# encoding: PKCS1 -# size: 4096 -# usages: -# - server auth -# hostnames: -# - "localhost" -# - "${ instance_name }.${base_domain}" -# ipAddresses: -# static: -# - 127.0.0.1 -# dnsLookup: -# - "${ instance_name }.${base_domain}" -# ttl: 100h -# hostPath: "/tmp/keep/certs/etcd-server" + - name: etcd-peer + issuerRef: + name: etcd-peer + vault: + role: "etcd-peer" + path: "clusters/cluster-1/pki/etcd" + spec: + subject: + commonName: custom:etcd-peer + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 4096 + usages: + - server auth + - client auth + hostnames: + - "localhost" + # - "${ instance_name }.${base_domain}" + ipAddresses: + static: + - 127.0.0.1 + # dnsLookup: + # - "${ instance_name }.${base_domain}" + ttl: 100h + renewBefore: 50h + hostPath: "/tmp/keep/certs/" -# - name: etcd-kube-apiserver-client -# issuerRef: -# name: etcd-client -# vault: -# role: "etcd-client" -# path: "clusters/cluster-1/pki/etcd" -# spec: -# commonName: custom:etcd-kube-apiserver-client -# privateKey: -# algorithm: RSA -# encoding: PKCS1 -# size: 4096 -# usages: -# - client auth -# ttl: 100h -# renewBefore: 360h -# hostPath: "/tmp/keep/certs/etcd-kube-apiserver-client" + - name: etcd-server + issuerRef: + name: etcd-server + vault: + role: "etcd-server" + path: "clusters/cluster-1/pki/etcd" + spec: + subject: + commonName: custom:etcd-server + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 4096 + usages: + - server auth + hostnames: + - "localhost" + # - "${ instance_name }.${base_domain}" + ipAddresses: + static: + - 127.0.0.1 + # dnsLookup: + # - "${ instance_name }.${base_domain}" + ttl: 100h + renewBefore: 50h + hostPath: "/tmp/keep/certs/" -# # keys: -# # - name: kube-sa -# # host_path: /tmp/keep/certs/kube-sa -# # privateKey: -# # algorithm: RSA -# # encoding: PKCS1 -# # size: 2048 -# # public: true -# # vault: -# # kv: "clusters/cluster-1/kv" + - name: etcd-kube-apiserver-client + issuerRef: + name: etcd-client + vault: + role: "etcd-client" + path: "clusters/cluster-1/pki/etcd" + spec: + subject: + commonName: custom:etcd-kube-apiserver-client + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 4096 + usages: + - client auth + ttl: 100h + renewBefore: 50h + hostPath: "/tmp/keep/certs/" + +# keys: +# - name: kube-sa +# host_path: /tmp/keep/certs/kube-sa +# privateKey: +# algorithm: RSA +# encoding: PKCS1 +# size: 2048 +# public: true +# vault: +# kv: "clusters/cluster-1/kv" From c02e0aad52c46dd004029fe9274066a6a6b30047 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 6 Sep 2022 10:41:17 +0300 Subject: [PATCH 133/220] fix --- internal/config/types.go | 2 +- test.yaml | 420 ++++++++++++++++++++------------------- 2 files changed, 212 insertions(+), 210 deletions(-) diff --git a/internal/config/types.go b/internal/config/types.go index e6a507b..ccf6715 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -59,7 +59,7 @@ type Auth struct { } type KV struct { - Path string `yaml:"paths"` + Path string `yaml:"path"` } type Bootstrap struct { diff --git a/test.yaml b/test.yaml index 8ea01bd..451c7ff 100644 --- a/test.yaml +++ b/test.yaml @@ -1,49 +1,49 @@ --- issuers: - - name: front-proxy-ca - vault: - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath - timeout: 15s + # - name: front-proxy-ca + # vault: + # server: "http://51.250.67.8:9200" + # auth: + # caBundle: "" + # tlsInsecure: true + # bootstrap: + # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ + # appRole: + # name: "test-role" + # path: "clusters/cluster-1/approle" + # roleIDLocalPath: /tmp/keep/roleIDLocalPath + # secretIDLocalPath: /tmp/keep/secretIDLocalPath + # timeout: 15s - - name: front-proxy-client - vault: - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath - timeout: 15s + # - name: front-proxy-client + # vault: + # server: "http://51.250.67.8:9200" + # auth: + # caBundle: "" + # tlsInsecure: true + # bootstrap: + # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ + # appRole: + # name: "test-role" + # path: "clusters/cluster-1/approle" + # roleIDLocalPath: /tmp/keep/roleIDLocalPath + # secretIDLocalPath: /tmp/keep/secretIDLocalPath + # timeout: 15s - - name: kubernetes-ca - vault: - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath - timeout: 15s + # - name: kubernetes-ca + # vault: + # server: "http://51.250.67.8:9200" + # auth: + # caBundle: "" + # tlsInsecure: true + # bootstrap: + # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ + # appRole: + # name: "test-role" + # path: "clusters/cluster-1/approle" + # roleIDLocalPath: /tmp/keep/roleIDLocalPath + # secretIDLocalPath: /tmp/keep/secretIDLocalPath + # timeout: 15s - name: kube-apiserver-server vault: @@ -61,184 +61,186 @@ issuers: path: "clusters/cluster-1/approle" roleIDLocalPath: /tmp/keep/roleIDLocalPath secretIDLocalPath: /tmp/keep/secretIDLocalPath + kv: + path: "path" timeout: 15s - - name: kube-apiserver-kubelet-client - vault: - role: - name: "kube-apiserver" - path: "clusters/cluster-1/pki/kubernetes" - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath - timeout: 15s + # - name: kube-apiserver-kubelet-client + # vault: + # role: + # name: "kube-apiserver" + # path: "clusters/cluster-1/pki/kubernetes" + # server: "http://51.250.67.8:9200" + # auth: + # caBundle: "" + # tlsInsecure: true + # bootstrap: + # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ + # appRole: + # name: "test-role" + # path: "clusters/cluster-1/approle" + # roleIDLocalPath: /tmp/keep/roleIDLocalPath + # secretIDLocalPath: /tmp/keep/secretIDLocalPath + # timeout: 15s - - name: kube-controller-manager-client - vault: - role: - name: "kube-controller-manager-client" - path: "clusters/cluster-1/pki/kubernetes" - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath - timeout: 15s + # - name: kube-controller-manager-client + # vault: + # role: + # name: "kube-controller-manager-client" + # path: "clusters/cluster-1/pki/kubernetes" + # server: "http://51.250.67.8:9200" + # auth: + # caBundle: "" + # tlsInsecure: true + # bootstrap: + # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ + # appRole: + # name: "test-role" + # path: "clusters/cluster-1/approle" + # roleIDLocalPath: /tmp/keep/roleIDLocalPath + # secretIDLocalPath: /tmp/keep/secretIDLocalPath + # timeout: 15s - - name: kube-controller-manager-server - vault: - role: - name: "kube-controller-manager-server" - path: "clusters/cluster-1/pki/kubernetes" - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath - timeout: 15s + # - name: kube-controller-manager-server + # vault: + # role: + # name: "kube-controller-manager-server" + # path: "clusters/cluster-1/pki/kubernetes" + # server: "http://51.250.67.8:9200" + # auth: + # caBundle: "" + # tlsInsecure: true + # bootstrap: + # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ + # appRole: + # name: "test-role" + # path: "clusters/cluster-1/approle" + # roleIDLocalPath: /tmp/keep/roleIDLocalPath + # secretIDLocalPath: /tmp/keep/secretIDLocalPath + # timeout: 15s - - name: kube-scheduler-server - vault: - role: - name: "kube-scheduler-server" - path: "clusters/cluster-1/pki/kubernetes" - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath - timeout: 15s + # - name: kube-scheduler-server + # vault: + # role: + # name: "kube-scheduler-server" + # path: "clusters/cluster-1/pki/kubernetes" + # server: "http://51.250.67.8:9200" + # auth: + # caBundle: "" + # tlsInsecure: true + # bootstrap: + # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ + # appRole: + # name: "test-role" + # path: "clusters/cluster-1/approle" + # roleIDLocalPath: /tmp/keep/roleIDLocalPath + # secretIDLocalPath: /tmp/keep/secretIDLocalPath + # timeout: 15s - - name: kube-scheduler-client - vault: - role: - name: "kube-scheduler-client" - path: "clusters/cluster-1/pki/kubernetes" - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath - timeout: 15s + # - name: kube-scheduler-client + # vault: + # role: + # name: "kube-scheduler-client" + # path: "clusters/cluster-1/pki/kubernetes" + # server: "http://51.250.67.8:9200" + # auth: + # caBundle: "" + # tlsInsecure: true + # bootstrap: + # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ + # appRole: + # name: "test-role" + # path: "clusters/cluster-1/approle" + # roleIDLocalPath: /tmp/keep/roleIDLocalPath + # secretIDLocalPath: /tmp/keep/secretIDLocalPath + # timeout: 15s - - name: kubelet-client - vault: - role: - name: "kubelet-client" - path: "clusters/cluster-1/pki/kubernetes" - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath - timeout: 15s + # - name: kubelet-client + # vault: + # role: + # name: "kubelet-client" + # path: "clusters/cluster-1/pki/kubernetes" + # server: "http://51.250.67.8:9200" + # auth: + # caBundle: "" + # tlsInsecure: true + # bootstrap: + # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ + # appRole: + # name: "test-role" + # path: "clusters/cluster-1/approle" + # roleIDLocalPath: /tmp/keep/roleIDLocalPath + # secretIDLocalPath: /tmp/keep/secretIDLocalPath + # timeout: 15s - - name: etcd-ca - vault: - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath - timeout: 15s + # - name: etcd-ca + # vault: + # server: "http://51.250.67.8:9200" + # auth: + # caBundle: "" + # tlsInsecure: true + # bootstrap: + # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ + # appRole: + # name: "test-role" + # path: "clusters/cluster-1/approle" + # roleIDLocalPath: /tmp/keep/roleIDLocalPath + # secretIDLocalPath: /tmp/keep/secretIDLocalPath + # timeout: 15s - - name: etcd-peer - vault: - role: - name: "etcd-peer" - path: "clusters/cluster-1/pki/etcd" - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath - timeout: 15s + # - name: etcd-peer + # vault: + # role: + # name: "etcd-peer" + # path: "clusters/cluster-1/pki/etcd" + # server: "http://51.250.67.8:9200" + # auth: + # caBundle: "" + # tlsInsecure: true + # bootstrap: + # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ + # appRole: + # name: "test-role" + # path: "clusters/cluster-1/approle" + # roleIDLocalPath: /tmp/keep/roleIDLocalPath + # secretIDLocalPath: /tmp/keep/secretIDLocalPath + # timeout: 15s - - name: etcd-server - vault: - role: - name: "etcd-server" - path: "clusters/cluster-1/pki/etcd" - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath - timeout: 15s + # - name: etcd-server + # vault: + # role: + # name: "etcd-server" + # path: "clusters/cluster-1/pki/etcd" + # server: "http://51.250.67.8:9200" + # auth: + # caBundle: "" + # tlsInsecure: true + # bootstrap: + # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ + # appRole: + # name: "test-role" + # path: "clusters/cluster-1/approle" + # roleIDLocalPath: /tmp/keep/roleIDLocalPath + # secretIDLocalPath: /tmp/keep/secretIDLocalPath + # timeout: 15s - - name: etcd-client - vault: - role: - name: "etcd-client" - path: "clusters/cluster-1/pki/etcd" - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath - timeout: 15s + # - name: etcd-client + # vault: + # role: + # name: "etcd-client" + # path: "clusters/cluster-1/pki/etcd" + # server: "http://51.250.67.8:9200" + # auth: + # caBundle: "" + # tlsInsecure: true + # bootstrap: + # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ + # appRole: + # name: "test-role" + # path: "clusters/cluster-1/approle" + # roleIDLocalPath: /tmp/keep/roleIDLocalPath + # secretIDLocalPath: /tmp/keep/secretIDLocalPath + # timeout: 15s certificates: # - name: front-proxy-ca From 529bfbc56a2be74faf29979ec138b574fd4c55e1 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 6 Sep 2022 10:44:59 +0300 Subject: [PATCH 134/220] resolver --- internal/resource/utils.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/internal/resource/utils.go b/internal/resource/utils.go index e5bcb2b..4b35c03 100644 --- a/internal/resource/utils.go +++ b/internal/resource/utils.go @@ -106,9 +106,9 @@ func getIPAddresses(cfg config.IPAddresses) []net.IP { ipAddresses := make(map[string]net.IP) for _, ip := range cfg.Static { - ip := net.IP(ip) - if ip.To4() != nil { - ipAddresses[ip.String()] = ip + netIP := net.IP(ip) + if netIP.To4() != nil { + ipAddresses[ip] = netIP } } @@ -143,9 +143,11 @@ func getIPAddresses(cfg config.IPAddresses) []net.IP { } } - r := make([]net.IP, 0, len(ipAddresses)) + r := make([]net.IP, len(ipAddresses)) + i := 0 for _, ip := range ipAddresses { - r = append(r, ip) + copy(r[i], ip) + i++ } return r } From c765faee65f22a4b8a9dd371b9f75d13cd32279e Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 6 Sep 2022 20:45:15 +0300 Subject: [PATCH 135/220] fix --- internal/resource/utils.go | 8 +- test.yaml | 531 ++++++++++++++++++------------------- 2 files changed, 268 insertions(+), 271 deletions(-) diff --git a/internal/resource/utils.go b/internal/resource/utils.go index 4b35c03..1602de8 100644 --- a/internal/resource/utils.go +++ b/internal/resource/utils.go @@ -106,7 +106,7 @@ func getIPAddresses(cfg config.IPAddresses) []net.IP { ipAddresses := make(map[string]net.IP) for _, ip := range cfg.Static { - netIP := net.IP(ip) + netIP := net.ParseIP(ip) if netIP.To4() != nil { ipAddresses[ip] = netIP } @@ -143,11 +143,9 @@ func getIPAddresses(cfg config.IPAddresses) []net.IP { } } - r := make([]net.IP, len(ipAddresses)) - i := 0 + r := make([]net.IP, 0, len(ipAddresses)) for _, ip := range ipAddresses { - copy(r[i], ip) - i++ + r = append(r, ip) } return r } diff --git a/test.yaml b/test.yaml index f891b3c..062f45e 100644 --- a/test.yaml +++ b/test.yaml @@ -243,50 +243,50 @@ issuers: # timeout: 15s certificates: - - name: front-proxy-ca - issuerRef: - name: front-proxy-ca - isCa: true - ca: - exportedKey: false - generate: false - vault: - role: "" - path: "clusters/cluster-1/pki/front-proxy" - rootCAPath: "clusters/cluster-1/pki/root" - hostPath: /tmp/keep/certs/ + # - name: front-proxy-ca + # issuerRef: + # name: front-proxy-ca + # isCa: true + # ca: + # exportedKey: false + # generate: false + # vault: + # role: "" + # path: "clusters/cluster-1/pki/front-proxy" + # rootCAPath: "clusters/cluster-1/pki/root" + # hostPath: /tmp/keep/certs/ - - name: front-proxy-client - issuerRef: - name: front-proxy-client - vault: - role: "front-proxy-client" - path: "clusters/cluster-1/pki/front-proxy" - spec: - subject: - commonName: custom:front-proxy-client - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - client auth - ttl: 100h - renewBefore: 50h - hostPath: "/tmp/keep/certs/" + # - name: front-proxy-client + # issuerRef: + # name: front-proxy-client + # vault: + # role: "front-proxy-client" + # path: "clusters/cluster-1/pki/front-proxy" + # spec: + # subject: + # commonName: custom:front-proxy-client + # privateKey: + # algorithm: RSA + # encoding: PKCS1 + # size: 4096 + # usages: + # - client auth + # ttl: 100h + # renewBefore: 50h + # hostPath: "/tmp/keep/certs/" - - name: kubernetes-ca - issuerRef: - name: kubernetes-ca - isCa: true - ca: - exportedKey: false - generate: false - vault: - role: "" - path: "clusters/cluster-1/pki/kubernetes" - rootCAPath: "clusters/cluster-1/pki/root" - hostPath: /tmp/keep/certs/ + # - name: kubernetes-ca + # issuerRef: + # name: kubernetes-ca + # isCa: true + # ca: + # exportedKey: false + # generate: false + # vault: + # role: "" + # path: "clusters/cluster-1/pki/kubernetes" + # rootCAPath: "clusters/cluster-1/pki/root" + # hostPath: /tmp/keep/certs/ - name: kube-apiserver-server issuerRef: @@ -322,237 +322,236 @@ certificates: ttl: 100h hostPath: "/tmp/keep/certs/" +# - name: kube-apiserver-kubelet-client +# issuerRef: +# name: kube-apiserver-kubelet-client +# vault: +# role: "kube-apiserver-kubelet-client" +# path: "clusters/cluster-1/pki/kubernetes" +# spec: +# privateKey: +# algorithm: RSA +# encoding: PKCS1 +# size: 4096 +# usages: +# - client auth +# subject: +# commonName: custom:kube-apiserver-kubelet-client +# organizationalUnits: +# - system:masters +# ttl: 100h +# renewBefore: 50h +# hostPath: "/tmp/keep/certs/" - - name: kube-apiserver-kubelet-client - issuerRef: - name: kube-apiserver-kubelet-client - vault: - role: "kube-apiserver-kubelet-client" - path: "clusters/cluster-1/pki/kubernetes" - spec: - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - client auth - subject: - commonName: custom:kube-apiserver-kubelet-client - organizationalUnits: - - system:masters - ttl: 100h - renewBefore: 50h - hostPath: "/tmp/keep/certs/" - - - name: kube-controller-manager-client - issuerRef: - name: kube-controller-manager-client - vault: - role: "kube-controller-manager-client" - path: "clusters/cluster-1/pki/kubernetes" - spec: - subject: - commonName: system:kube-controller-manager - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - client auth - ttl: 100h - renewBefore: 50h - hostPath: "/tmp/keep/certs/" - - - name: kube-controller-manager-server - issuerRef: - name: kube-controller-manager-server - vault: - role: "kube-controller-manager-server" - path: "clusters/cluster-1/pki/kubernetes" - spec: - subject: - commonName: system:kube-controller-manager - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - server auth - hostnames: - - "localhost" - - "kube-controller-manager.default" - - "kube-controller-manager.default.svc" - - "kube-controller-manager.default.svc.cluster" - - "kube-controller-manager.default.svc.cluster.local" - ipAddresses: - static: - - 127.0.0.1 - ttl: 100h - renewBefore: 50h - hostPath: "/tmp/keep/certs/" +# - name: kube-controller-manager-client +# issuerRef: +# name: kube-controller-manager-client +# vault: +# role: "kube-controller-manager-client" +# path: "clusters/cluster-1/pki/kubernetes" +# spec: +# subject: +# commonName: system:kube-controller-manager +# privateKey: +# algorithm: RSA +# encoding: PKCS1 +# size: 4096 +# usages: +# - client auth +# ttl: 100h +# renewBefore: 50h +# hostPath: "/tmp/keep/certs/" - - name: kube-scheduler-server - issuerRef: - name: kube-scheduler-server - vault: - role: "kube-scheduler-server" - path: "clusters/cluster-1/pki/kubernetes" - spec: - subject: - commonName: system:kube-scheduler - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - server auth - hostnames: - - "localhost" - - "kube-scheduler.default" - - "kube-scheduler.default.svc" - - "kube-scheduler.default.svc.cluster" - - "kube-scheduler.default.svc.cluster.local" - ipAddresses: - static: - - 127.0.0.1 - ttl: 100h - renewBefore: 50h - hostPath: "/tmp/keep/certs/" +# - name: kube-controller-manager-server +# issuerRef: +# name: kube-controller-manager-server +# vault: +# role: "kube-controller-manager-server" +# path: "clusters/cluster-1/pki/kubernetes" +# spec: +# subject: +# commonName: system:kube-controller-manager +# privateKey: +# algorithm: RSA +# encoding: PKCS1 +# size: 4096 +# usages: +# - server auth +# hostnames: +# - "localhost" +# - "kube-controller-manager.default" +# - "kube-controller-manager.default.svc" +# - "kube-controller-manager.default.svc.cluster" +# - "kube-controller-manager.default.svc.cluster.local" +# ipAddresses: +# static: +# - 127.0.0.1 +# ttl: 100h +# renewBefore: 50h +# hostPath: "/tmp/keep/certs/" - - name: kube-scheduler-client - issuerRef: - name: kube-scheduler-client - vault: - role: "kube-scheduler-client" - path: "clusters/cluster-1/pki/kubernetes" - spec: - subject: - commonName: system:kube-scheduler - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - client auth - ttl: 100h - renewBefore: 50h - hostPath: "/tmp/keep/certs/" +# - name: kube-scheduler-server +# issuerRef: +# name: kube-scheduler-server +# vault: +# role: "kube-scheduler-server" +# path: "clusters/cluster-1/pki/kubernetes" +# spec: +# subject: +# commonName: system:kube-scheduler +# privateKey: +# algorithm: RSA +# encoding: PKCS1 +# size: 4096 +# usages: +# - server auth +# hostnames: +# - "localhost" +# - "kube-scheduler.default" +# - "kube-scheduler.default.svc" +# - "kube-scheduler.default.svc.cluster" +# - "kube-scheduler.default.svc.cluster.local" +# ipAddresses: +# static: +# - 127.0.0.1 +# ttl: 100h +# renewBefore: 50h +# hostPath: "/tmp/keep/certs/" - - name: kubelet-client - issuerRef: - name: kubelet-client - vault: - role: "kubelet-client" - path: "clusters/cluster-1/pki/kubernetes" - spec: - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - subject: - commonName: system:node:${instance_name} - organizations: - - system:nodes - usages: - - client auth - ttl: 100h - renewBefore: 50h - hostPath: "/tmp/keep/certs/" +# - name: kube-scheduler-client +# issuerRef: +# name: kube-scheduler-client +# vault: +# role: "kube-scheduler-client" +# path: "clusters/cluster-1/pki/kubernetes" +# spec: +# subject: +# commonName: system:kube-scheduler +# privateKey: +# algorithm: RSA +# encoding: PKCS1 +# size: 4096 +# usages: +# - client auth +# ttl: 100h +# renewBefore: 50h +# hostPath: "/tmp/keep/certs/" - - name: etcd-ca - issuerRef: - name: etcd-ca - isCa: true - ca: - exportedKey: false - generate: false - vault: - role: "" - path: "clusters/cluster-1/pki/etcd" - rootCAPath: "clusters/cluster-1/pki/root" - hostPath: /tmp/keep/certs/ +# - name: kubelet-client +# issuerRef: +# name: kubelet-client +# vault: +# role: "kubelet-client" +# path: "clusters/cluster-1/pki/kubernetes" +# spec: +# privateKey: +# algorithm: RSA +# encoding: PKCS1 +# size: 4096 +# subject: +# commonName: system:node:${instance_name} +# organizations: +# - system:nodes +# usages: +# - client auth +# ttl: 100h +# renewBefore: 50h +# hostPath: "/tmp/keep/certs/" - - name: etcd-peer - issuerRef: - name: etcd-peer - vault: - role: "etcd-peer" - path: "clusters/cluster-1/pki/etcd" - spec: - subject: - commonName: custom:etcd-peer - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - server auth - - client auth - hostnames: - - "localhost" - # - "${ instance_name }.${base_domain}" - ipAddresses: - static: - - 127.0.0.1 - # dnsLookup: - # - "${ instance_name }.${base_domain}" - ttl: 100h - renewBefore: 50h - hostPath: "/tmp/keep/certs/" +# - name: etcd-ca +# issuerRef: +# name: etcd-ca +# isCa: true +# ca: +# exportedKey: false +# generate: false +# vault: +# role: "" +# path: "clusters/cluster-1/pki/etcd" +# rootCAPath: "clusters/cluster-1/pki/root" +# hostPath: /tmp/keep/certs/ - - name: etcd-server - issuerRef: - name: etcd-server - vault: - role: "etcd-server" - path: "clusters/cluster-1/pki/etcd" - spec: - subject: - commonName: custom:etcd-server - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - server auth - hostnames: - - "localhost" - # - "${ instance_name }.${base_domain}" - ipAddresses: - static: - - 127.0.0.1 - # dnsLookup: - # - "${ instance_name }.${base_domain}" - ttl: 100h - renewBefore: 50h - hostPath: "/tmp/keep/certs/" +# - name: etcd-peer +# issuerRef: +# name: etcd-peer +# vault: +# role: "etcd-peer" +# path: "clusters/cluster-1/pki/etcd" +# spec: +# subject: +# commonName: custom:etcd-peer +# privateKey: +# algorithm: RSA +# encoding: PKCS1 +# size: 4096 +# usages: +# - server auth +# - client auth +# hostnames: +# - "localhost" +# # - "${ instance_name }.${base_domain}" +# ipAddresses: +# static: +# - 127.0.0.1 +# # dnsLookup: +# # - "${ instance_name }.${base_domain}" +# ttl: 100h +# renewBefore: 50h +# hostPath: "/tmp/keep/certs/" - - name: etcd-kube-apiserver-client - issuerRef: - name: etcd-client - vault: - role: "etcd-client" - path: "clusters/cluster-1/pki/etcd" - spec: - subject: - commonName: custom:etcd-kube-apiserver-client - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - client auth - ttl: 100h - renewBefore: 50h - hostPath: "/tmp/keep/certs/" +# - name: etcd-server +# issuerRef: +# name: etcd-server +# vault: +# role: "etcd-server" +# path: "clusters/cluster-1/pki/etcd" +# spec: +# subject: +# commonName: custom:etcd-server +# privateKey: +# algorithm: RSA +# encoding: PKCS1 +# size: 4096 +# usages: +# - server auth +# hostnames: +# - "localhost" +# # - "${ instance_name }.${base_domain}" +# ipAddresses: +# static: +# - 127.0.0.1 +# # dnsLookup: +# # - "${ instance_name }.${base_domain}" +# ttl: 100h +# renewBefore: 50h +# hostPath: "/tmp/keep/certs/" -# keys: -# - name: kube-sa -# host_path: /tmp/keep/certs/kube-sa -# privateKey: -# algorithm: RSA -# encoding: PKCS1 -# size: 2048 -# public: true +# - name: etcd-kube-apiserver-client +# issuerRef: +# name: etcd-client # vault: -# kv: "clusters/cluster-1/kv" +# role: "etcd-client" +# path: "clusters/cluster-1/pki/etcd" +# spec: +# subject: +# commonName: custom:etcd-kube-apiserver-client +# privateKey: +# algorithm: RSA +# encoding: PKCS1 +# size: 4096 +# usages: +# - client auth +# ttl: 100h +# renewBefore: 50h +# hostPath: "/tmp/keep/certs/" + +# # keys: +# # - name: kube-sa +# # host_path: /tmp/keep/certs/kube-sa +# # privateKey: +# # algorithm: RSA +# # encoding: PKCS1 +# # size: 2048 +# # public: true +# # vault: +# # kv: "clusters/cluster-1/kv" From 62eabd23a9556dedef49bcb535fe68c6acb1dfe5 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 8 Sep 2022 16:14:44 +0300 Subject: [PATCH 136/220] kv --- config-struct.yaml | 7 +++++ internal/config/types.go | 42 ++++++++++++++++----------- internal/resource/key.go | 4 ++- internal/resource/resource.go | 13 +++++++++ internal/resource/secret.go | 53 +++++++++++++++++++++++++++++++++++ 5 files changed, 101 insertions(+), 18 deletions(-) create mode 100644 internal/resource/secret.go diff --git a/config-struct.yaml b/config-struct.yaml index 79e10c7..8ae02fb 100644 --- a/config-struct.yaml +++ b/config-struct.yaml @@ -59,3 +59,10 @@ keys: # Описывает список доступных keys issuerRef: # IssuerRef references a properly configured ACME-type Issuer which should be used to create this Order. If the Issuer does not exist, processing will be retried. If the Issuer is not an 'ACME' Issuer, an error will be returned and the Order will be marked as failed. name: string # Имя вызываемого ISSUER hostPath: string # путь, где будет размещен секрет по маске ${hostPathCert}/${keyName} + +secrets: # Описывает список доступных secrete + - name: # Имя secrete + issuerRef: # IssuerRef references a properly configured ACME-type Issuer which should be used to create this Order. If the Issuer does not exist, processing will be retried. If the Issuer is not an 'ACME' Issuer, an error will be returned and the Order will be marked as failed. + name: string # Имя вызываемого ISSUER + key: string + hostPath: string # путь, где будет размещен секрет по маске ${hostPathCert}/${keyName} diff --git a/internal/config/types.go b/internal/config/types.go index ccf6715..e1548e1 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -15,6 +15,7 @@ type Issuer struct { type Resources struct { Certificates []Certificate `yaml:"certificates"` Keys []Key `yaml:"keys"` + Secrets []Secret `yaml:"secret"` } type Certificate struct { @@ -35,13 +36,11 @@ type Key struct { HostPath string `yaml:"hostPath"` } -type IssuerRef struct { - Name string `yaml:"name"` -} - -type CA struct { - ExportedKey bool `yaml:"exportedKey"` - Generate bool `yaml:"generate"` +type Secret struct { + Name string `yaml:"name"` + IssuerRef IssuerRef `yaml:"issuerRef"` + Key string `yaml:"key"` + HostPath string `yaml:"hostPath"` } type Vault struct { @@ -58,10 +57,6 @@ type Auth struct { AppRole AppRole `yaml:"appRole"` } -type KV struct { - Path string `yaml:"path"` -} - type Bootstrap struct { Token string `yaml:"token"` } @@ -73,6 +68,19 @@ type AppRole struct { SecretIDLocalPath string `yaml:"secretIDLocalPath"` } +type KV struct { + Path string `yaml:"path"` +} + +type IssuerRef struct { + Name string `yaml:"name"` +} + +type CA struct { + ExportedKey bool `yaml:"exportedKey"` + Generate bool `yaml:"generate"` +} + type Spec struct { Subject Subject `yaml:"subject"` PrivateKey PrivateKey `yaml:"privateKey"` @@ -93,6 +101,12 @@ type Subject struct { SerialNumber string `yaml:"serialNumber"` } +type CertVault struct { + Role string `yaml:"role"` + Path string `yaml:"path"` + RootCAPath string `yaml:"rootCAPath"` +} + type PrivateKey struct { Algorithm string `yaml:"algorithm"` Encoding string `yaml:"encoding"` @@ -104,9 +118,3 @@ type IPAddresses struct { Interfaces []string `yaml:"interfaces"` DNSLookup []string `yaml:"dnsLookup"` } - -type CertVault struct { - Role string `yaml:"role"` - Path string `yaml:"path"` - RootCAPath string `yaml:"rootCAPath"` -} diff --git a/internal/resource/key.go b/internal/resource/key.go index 6c2c115..8831c3f 100644 --- a/internal/resource/key.go +++ b/internal/resource/key.go @@ -2,6 +2,7 @@ package resource import ( "fmt" + "path" "go.uber.org/zap" @@ -20,7 +21,7 @@ func (s *resource) checkKey(i config.Key) { zap.L().Debug("rsa is read", zap.String("name", i.Name)) } - if err := s.storeKey(i.HostPath, private, public); err != nil { + if err := s.storeKey(path.Join(i.HostPath, i.Name), private, public); err != nil { zap.L().Error( "store rsa in host", zap.String("name", i.Name), @@ -39,6 +40,7 @@ func (s *resource) readKey(i config.Key) (private []byte, public []byte, err err return } + // TODO: check private, public = []byte(storedRSA["private"].(string)), []byte(storedRSA["public"].(string)) return } diff --git a/internal/resource/resource.go b/internal/resource/resource.go index 0b2d1e1..000e04c 100644 --- a/internal/resource/resource.go +++ b/internal/resource/resource.go @@ -12,6 +12,7 @@ type resource struct { vault controller.Vault certificate map[string]config.Certificate key map[string]config.Key + secret map[string]config.Secret } func Preparing( @@ -21,6 +22,7 @@ func Preparing( vault: vault, certificate: make(map[string]config.Certificate), key: make(map[string]config.Key), + secret: make(map[string]config.Secret), } } @@ -49,6 +51,14 @@ func (s *resource) Check() { s.checkKey(k) }(key) } + + zap.L().Debug("secrets") + for _, secret := range s.secret { + wg.Add(1) + go func(secret config.Secret) { + s.checkSecret(secret) + }(secret) + } wg.Wait() zap.L().Debug("done") @@ -61,5 +71,8 @@ func (s *resource) Add(r config.Resources) { for _, key := range r.Keys { s.key[key.Name] = key } + for _, secret := range r.Secrets { + s.secret[secret.Name] = secret + } s.Check() } diff --git a/internal/resource/secret.go b/internal/resource/secret.go new file mode 100644 index 0000000..88700fe --- /dev/null +++ b/internal/resource/secret.go @@ -0,0 +1,53 @@ +package resource + +import ( + "fmt" + "os" + "path" + + "go.uber.org/zap" + + "github.com/fraima/key-keeper/internal/config" +) + +func (s *resource) checkSecret(i config.Secret) { + secret, err := s.readSecret(i) + if err != nil { + zap.L().Warn( + "read secret", + zap.String("name", i.Name), + zap.Error(err), + ) + } else { + zap.L().Debug("secret is read", zap.String("name", i.Name)) + } + + if err := s.storeSecret(path.Join(i.HostPath, i.Name), secret); err != nil { + zap.L().Error( + "store secrete in host", + zap.String("name", i.Name), + zap.String("path", i.HostPath), + zap.Error(err), + ) + return + } + zap.L().Debug("secret is stored", zap.String("name", i.Name)) +} + +func (s *resource) readSecret(i config.Secret) (secrete []byte, err error) { + storedRSA, err := s.vault.Get(i.Name) + if err != nil { + err = fmt.Errorf("get from vault_kv : %w", err) + return + } + + secrete = []byte(storedRSA[i.Key].(string)) + return +} + +func (s *resource) storeSecret(path string, secret []byte) error { + if err := os.WriteFile(path, secret, 0600); err != nil { + return fmt.Errorf("failed to save secrete with path %s: %w", path, err) + } + return nil +} From 880837e3f1b25fd07fcf154f7e9708d5995b672c Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 8 Sep 2022 16:29:47 +0300 Subject: [PATCH 137/220] fix --- internal/controller/controller.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 0a388a7..7ea89e2 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -137,5 +137,11 @@ func (s *controller) separateResources(cfg config.Resources) map[string]config.R resources.Keys = append(resources.Keys, key) r[key.IssuerRef.Name] = resources } + + for _, secret := range cfg.Secrets { + resources := r[secret.IssuerRef.Name] + resources.Secrets = append(resources.Secrets, secret) + r[secret.IssuerRef.Name] = resources + } return r } From 1323f9e247d32041fed53ffaf58de8a9f7b68eb7 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 8 Sep 2022 16:49:28 +0300 Subject: [PATCH 138/220] fix --- example.yaml | 77 ------ internal/config/config.go | 1 + internal/config/types.go | 2 +- test.yaml | 541 ++------------------------------------ 4 files changed, 31 insertions(+), 590 deletions(-) delete mode 100644 example.yaml diff --git a/example.yaml b/example.yaml deleted file mode 100644 index dea3e7a..0000000 --- a/example.yaml +++ /dev/null @@ -1,77 +0,0 @@ ---- -issuers: - - name: front-proxy-ca - vault: - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: $TOKEN - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath - timeout: 15s - - - name: kube-apiserver-server - vault: - role: - name: "kube-apiserver" - path: "clusters/cluster-1/pki/kubernetes" - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: $TOKEN - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - roleIDLocalPath: /tmp/keep/roleIDLocalPath - secretIDLocalPath: /tmp/keep/secretIDLocalPath - timeout: 15s - -certificates: - - name: front-proxy-ca - issuerRef: - name: front-proxy-ca - isCa: true - ca: - exportedKey: false - generate: false - vault: - role: "" - path: "clusters/cluster-1/pki/front-proxy" - rootCAPath: "clusters/cluster-1/pki/root" - hostPath: /tmp/keep/certs/front-proxy-ca - renewBefore: 24h - trigger: - - ls -al - - - name: kube-apiserver-server - spec: - subject: - organizations: - - system:masters - ous: [] - countries: [] - commonName: kube-apiserver-server - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 2048 - usages: - - server auth - - client auth - dnsNames: - - kube-apiserver-server - - www.example.com - ipAddresses: - - 127.0.0.1 - issuerRef: - name: kube-apiserver-server - hostPath: "/tmp/keep/certs/kube-apiserver/cert" - trigger: - - systemctl stop kube-apiserver.service \ No newline at end of file diff --git a/internal/config/config.go b/internal/config/config.go index a1f2863..c159524 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -53,6 +53,7 @@ func (s *config) GetNewConfig() (newCfg Config, err error) { newCfg.Issuers = append(newCfg.Issuers, cfg.Issuers...) newCfg.Resource.Certificates = append(newCfg.Resource.Certificates, cfg.Resource.Certificates...) newCfg.Resource.Keys = append(newCfg.Resource.Keys, cfg.Resource.Keys...) + newCfg.Resource.Secrets = append(newCfg.Resource.Secrets, cfg.Resource.Secrets...) s.oldConfig[path] = struct{}{} } diff --git a/internal/config/types.go b/internal/config/types.go index e1548e1..7e04db6 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -15,7 +15,7 @@ type Issuer struct { type Resources struct { Certificates []Certificate `yaml:"certificates"` Keys []Key `yaml:"keys"` - Secrets []Secret `yaml:"secret"` + Secrets []Secret `yaml:"secrets"` } type Certificate struct { diff --git a/test.yaml b/test.yaml index 062f45e..d323793 100644 --- a/test.yaml +++ b/test.yaml @@ -1,50 +1,5 @@ --- issuers: - # - name: front-proxy-ca - # vault: - # server: "http://51.250.67.8:9200" - # auth: - # caBundle: "" - # tlsInsecure: true - # bootstrap: - # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - # appRole: - # name: "test-role" - # path: "clusters/cluster-1/approle" - # roleIDLocalPath: /tmp/keep/roleIDLocalPath - # secretIDLocalPath: /tmp/keep/secretIDLocalPath - # timeout: 15s - - # - name: front-proxy-client - # vault: - # server: "http://51.250.67.8:9200" - # auth: - # caBundle: "" - # tlsInsecure: true - # bootstrap: - # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - # appRole: - # name: "test-role" - # path: "clusters/cluster-1/approle" - # roleIDLocalPath: /tmp/keep/roleIDLocalPath - # secretIDLocalPath: /tmp/keep/secretIDLocalPath - # timeout: 15s - - # - name: kubernetes-ca - # vault: - # server: "http://51.250.67.8:9200" - # auth: - # caBundle: "" - # tlsInsecure: true - # bootstrap: - # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - # appRole: - # name: "test-role" - # path: "clusters/cluster-1/approle" - # roleIDLocalPath: /tmp/keep/roleIDLocalPath - # secretIDLocalPath: /tmp/keep/secretIDLocalPath - # timeout: 15s - - name: kube-apiserver-server vault: role: @@ -65,312 +20,22 @@ issuers: path: "path" timeout: 15s - # - name: kube-apiserver-kubelet-client - # vault: - # role: - # name: "kube-apiserver" - # path: "clusters/cluster-1/pki/kubernetes" - # server: "http://51.250.67.8:9200" - # auth: - # caBundle: "" - # tlsInsecure: true - # bootstrap: - # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - # appRole: - # name: "test-role" - # path: "clusters/cluster-1/approle" - # roleIDLocalPath: /tmp/keep/roleIDLocalPath - # secretIDLocalPath: /tmp/keep/secretIDLocalPath - # timeout: 15s - - # - name: kube-controller-manager-client - # vault: - # role: - # name: "kube-controller-manager-client" - # path: "clusters/cluster-1/pki/kubernetes" - # server: "http://51.250.67.8:9200" - # auth: - # caBundle: "" - # tlsInsecure: true - # bootstrap: - # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - # appRole: - # name: "test-role" - # path: "clusters/cluster-1/approle" - # roleIDLocalPath: /tmp/keep/roleIDLocalPath - # secretIDLocalPath: /tmp/keep/secretIDLocalPath - # timeout: 15s - - # - name: kube-controller-manager-server - # vault: - # role: - # name: "kube-controller-manager-server" - # path: "clusters/cluster-1/pki/kubernetes" - # server: "http://51.250.67.8:9200" - # auth: - # caBundle: "" - # tlsInsecure: true - # bootstrap: - # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - # appRole: - # name: "test-role" - # path: "clusters/cluster-1/approle" - # roleIDLocalPath: /tmp/keep/roleIDLocalPath - # secretIDLocalPath: /tmp/keep/secretIDLocalPath - # timeout: 15s - - # - name: kube-scheduler-server - # vault: - # role: - # name: "kube-scheduler-server" - # path: "clusters/cluster-1/pki/kubernetes" - # server: "http://51.250.67.8:9200" - # auth: - # caBundle: "" - # tlsInsecure: true - # bootstrap: - # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - # appRole: - # name: "test-role" - # path: "clusters/cluster-1/approle" - # roleIDLocalPath: /tmp/keep/roleIDLocalPath - # secretIDLocalPath: /tmp/keep/secretIDLocalPath - # timeout: 15s - - # - name: kube-scheduler-client - # vault: - # role: - # name: "kube-scheduler-client" - # path: "clusters/cluster-1/pki/kubernetes" - # server: "http://51.250.67.8:9200" - # auth: - # caBundle: "" - # tlsInsecure: true - # bootstrap: - # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - # appRole: - # name: "test-role" - # path: "clusters/cluster-1/approle" - # roleIDLocalPath: /tmp/keep/roleIDLocalPath - # secretIDLocalPath: /tmp/keep/secretIDLocalPath - # timeout: 15s - - # - name: kubelet-client - # vault: - # role: - # name: "kubelet-client" - # path: "clusters/cluster-1/pki/kubernetes" - # server: "http://51.250.67.8:9200" - # auth: - # caBundle: "" - # tlsInsecure: true - # bootstrap: - # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - # appRole: - # name: "test-role" - # path: "clusters/cluster-1/approle" - # roleIDLocalPath: /tmp/keep/roleIDLocalPath - # secretIDLocalPath: /tmp/keep/secretIDLocalPath - # timeout: 15s - - # - name: etcd-ca - # vault: - # server: "http://51.250.67.8:9200" - # auth: - # caBundle: "" - # tlsInsecure: true - # bootstrap: - # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - # appRole: - # name: "test-role" - # path: "clusters/cluster-1/approle" - # roleIDLocalPath: /tmp/keep/roleIDLocalPath - # secretIDLocalPath: /tmp/keep/secretIDLocalPath - # timeout: 15s - - # - name: etcd-peer - # vault: - # role: - # name: "etcd-peer" - # path: "clusters/cluster-1/pki/etcd" - # server: "http://51.250.67.8:9200" - # auth: - # caBundle: "" - # tlsInsecure: true - # bootstrap: - # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - # appRole: - # name: "test-role" - # path: "clusters/cluster-1/approle" - # roleIDLocalPath: /tmp/keep/roleIDLocalPath - # secretIDLocalPath: /tmp/keep/secretIDLocalPath - # timeout: 15s - - # - name: etcd-server - # vault: - # role: - # name: "etcd-server" - # path: "clusters/cluster-1/pki/etcd" - # server: "http://51.250.67.8:9200" - # auth: - # caBundle: "" - # tlsInsecure: true - # bootstrap: - # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - # appRole: - # name: "test-role" - # path: "clusters/cluster-1/approle" - # roleIDLocalPath: /tmp/keep/roleIDLocalPath - # secretIDLocalPath: /tmp/keep/secretIDLocalPath - # timeout: 15s - - # - name: etcd-client - # vault: - # role: - # name: "etcd-client" - # path: "clusters/cluster-1/pki/etcd" - # server: "http://51.250.67.8:9200" - # auth: - # caBundle: "" - # tlsInsecure: true - # bootstrap: - # token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - # appRole: - # name: "test-role" - # path: "clusters/cluster-1/approle" - # roleIDLocalPath: /tmp/keep/roleIDLocalPath - # secretIDLocalPath: /tmp/keep/secretIDLocalPath - # timeout: 15s - -certificates: - # - name: front-proxy-ca - # issuerRef: - # name: front-proxy-ca - # isCa: true - # ca: - # exportedKey: false - # generate: false - # vault: - # role: "" - # path: "clusters/cluster-1/pki/front-proxy" - # rootCAPath: "clusters/cluster-1/pki/root" - # hostPath: /tmp/keep/certs/ - - # - name: front-proxy-client - # issuerRef: - # name: front-proxy-client - # vault: - # role: "front-proxy-client" - # path: "clusters/cluster-1/pki/front-proxy" - # spec: - # subject: - # commonName: custom:front-proxy-client - # privateKey: - # algorithm: RSA - # encoding: PKCS1 - # size: 4096 - # usages: - # - client auth - # ttl: 100h - # renewBefore: 50h - # hostPath: "/tmp/keep/certs/" - - # - name: kubernetes-ca - # issuerRef: - # name: kubernetes-ca - # isCa: true - # ca: - # exportedKey: false - # generate: false - # vault: - # role: "" - # path: "clusters/cluster-1/pki/kubernetes" - # rootCAPath: "clusters/cluster-1/pki/root" - # hostPath: /tmp/keep/certs/ - - - name: kube-apiserver-server +secrets: + - name: sa-key issuerRef: name: kube-apiserver-server - vault: - role: "kube-apiserver" - path: "clusters/cluster-1/pki/kubernetes" - spec: - subject: - commonName: custom:kube-apiserver-server - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - server auth - hostnames: - - "localhost" - - "kubernetes" - - "kubernetes.default" - - "kubernetes.default.svc" - - "kubernetes.default.svc.cluster" - - "kubernetes.default.svc.cluster.local" - - "api.cluster-1.dobry-kot.ru" - ipAddresses: - static: - - 127.0.0.1 - - 10.10.10.0 - interfaces: - - lo - dnsLookup: - - yandex.ru - - ttl: 100h - hostPath: "/tmp/keep/certs/" -# - name: kube-apiserver-kubelet-client -# issuerRef: -# name: kube-apiserver-kubelet-client -# vault: -# role: "kube-apiserver-kubelet-client" -# path: "clusters/cluster-1/pki/kubernetes" -# spec: -# privateKey: -# algorithm: RSA -# encoding: PKCS1 -# size: 4096 -# usages: -# - client auth -# subject: -# commonName: custom:kube-apiserver-kubelet-client -# organizationalUnits: -# - system:masters -# ttl: 100h -# renewBefore: 50h -# hostPath: "/tmp/keep/certs/" - -# - name: kube-controller-manager-client -# issuerRef: -# name: kube-controller-manager-client -# vault: -# role: "kube-controller-manager-client" -# path: "clusters/cluster-1/pki/kubernetes" -# spec: -# subject: -# commonName: system:kube-controller-manager -# privateKey: -# algorithm: RSA -# encoding: PKCS1 -# size: 4096 -# usages: -# - client auth -# ttl: 100h -# renewBefore: 50h -# hostPath: "/tmp/keep/certs/" - -# - name: kube-controller-manager-server + key: private + hostPath: /tmp/keep/certs/ +# certificates: +# - name: kube-apiserver-server # issuerRef: -# name: kube-controller-manager-server +# name: kube-apiserver-server # vault: -# role: "kube-controller-manager-server" +# role: "kube-apiserver" # path: "clusters/cluster-1/pki/kubernetes" # spec: # subject: -# commonName: system:kube-controller-manager +# commonName: custom:kube-apiserver-server # privateKey: # algorithm: RSA # encoding: PKCS1 @@ -379,179 +44,31 @@ certificates: # - server auth # hostnames: # - "localhost" -# - "kube-controller-manager.default" -# - "kube-controller-manager.default.svc" -# - "kube-controller-manager.default.svc.cluster" -# - "kube-controller-manager.default.svc.cluster.local" +# - "kubernetes" +# - "kubernetes.default" +# - "kubernetes.default.svc" +# - "kubernetes.default.svc.cluster" +# - "kubernetes.default.svc.cluster.local" +# - "api.cluster-1.dobry-kot.ru" # ipAddresses: # static: # - 127.0.0.1 -# ttl: 100h -# renewBefore: 50h -# hostPath: "/tmp/keep/certs/" +# - 10.10.10.0 +# interfaces: +# - lo +# dnsLookup: +# - yandex.ru -# - name: kube-scheduler-server -# issuerRef: -# name: kube-scheduler-server -# vault: -# role: "kube-scheduler-server" -# path: "clusters/cluster-1/pki/kubernetes" -# spec: -# subject: -# commonName: system:kube-scheduler -# privateKey: -# algorithm: RSA -# encoding: PKCS1 -# size: 4096 -# usages: -# - server auth -# hostnames: -# - "localhost" -# - "kube-scheduler.default" -# - "kube-scheduler.default.svc" -# - "kube-scheduler.default.svc.cluster" -# - "kube-scheduler.default.svc.cluster.local" -# ipAddresses: -# static: -# - 127.0.0.1 # ttl: 100h -# renewBefore: 50h # hostPath: "/tmp/keep/certs/" - -# - name: kube-scheduler-client -# issuerRef: -# name: kube-scheduler-client +# keys: +# - name: kube-sa +# host_path: /tmp/keep/certs/kube-sa +# privateKey: +# algorithm: RSA +# encoding: PKCS1 +# size: 2048 +# public: true # vault: -# role: "kube-scheduler-client" -# path: "clusters/cluster-1/pki/kubernetes" -# spec: -# subject: -# commonName: system:kube-scheduler -# privateKey: -# algorithm: RSA -# encoding: PKCS1 -# size: 4096 -# usages: -# - client auth -# ttl: 100h -# renewBefore: 50h -# hostPath: "/tmp/keep/certs/" - -# - name: kubelet-client -# issuerRef: -# name: kubelet-client -# vault: -# role: "kubelet-client" -# path: "clusters/cluster-1/pki/kubernetes" -# spec: -# privateKey: -# algorithm: RSA -# encoding: PKCS1 -# size: 4096 -# subject: -# commonName: system:node:${instance_name} -# organizations: -# - system:nodes -# usages: -# - client auth -# ttl: 100h -# renewBefore: 50h -# hostPath: "/tmp/keep/certs/" - -# - name: etcd-ca -# issuerRef: -# name: etcd-ca -# isCa: true -# ca: -# exportedKey: false -# generate: false -# vault: -# role: "" -# path: "clusters/cluster-1/pki/etcd" -# rootCAPath: "clusters/cluster-1/pki/root" -# hostPath: /tmp/keep/certs/ - -# - name: etcd-peer -# issuerRef: -# name: etcd-peer -# vault: -# role: "etcd-peer" -# path: "clusters/cluster-1/pki/etcd" -# spec: -# subject: -# commonName: custom:etcd-peer -# privateKey: -# algorithm: RSA -# encoding: PKCS1 -# size: 4096 -# usages: -# - server auth -# - client auth -# hostnames: -# - "localhost" -# # - "${ instance_name }.${base_domain}" -# ipAddresses: -# static: -# - 127.0.0.1 -# # dnsLookup: -# # - "${ instance_name }.${base_domain}" -# ttl: 100h -# renewBefore: 50h -# hostPath: "/tmp/keep/certs/" - -# - name: etcd-server -# issuerRef: -# name: etcd-server -# vault: -# role: "etcd-server" -# path: "clusters/cluster-1/pki/etcd" -# spec: -# subject: -# commonName: custom:etcd-server -# privateKey: -# algorithm: RSA -# encoding: PKCS1 -# size: 4096 -# usages: -# - server auth -# hostnames: -# - "localhost" -# # - "${ instance_name }.${base_domain}" -# ipAddresses: -# static: -# - 127.0.0.1 -# # dnsLookup: -# # - "${ instance_name }.${base_domain}" -# ttl: 100h -# renewBefore: 50h -# hostPath: "/tmp/keep/certs/" - -# - name: etcd-kube-apiserver-client -# issuerRef: -# name: etcd-client -# vault: -# role: "etcd-client" -# path: "clusters/cluster-1/pki/etcd" -# spec: -# subject: -# commonName: custom:etcd-kube-apiserver-client -# privateKey: -# algorithm: RSA -# encoding: PKCS1 -# size: 4096 -# usages: -# - client auth -# ttl: 100h -# renewBefore: 50h -# hostPath: "/tmp/keep/certs/" +# kv: "clusters/cluster-1/kv" -# # keys: -# # - name: kube-sa -# # host_path: /tmp/keep/certs/kube-sa -# # privateKey: -# # algorithm: RSA -# # encoding: PKCS1 -# # size: 2048 -# # public: true -# # vault: -# # kv: "clusters/cluster-1/kv" From 6d345661797f2faa4649e7ae258ec179ab6d2b07 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 12 Sep 2022 15:02:54 +0300 Subject: [PATCH 139/220] done --- config-struct.yaml | 3 +-- internal/config/types.go | 7 +++---- internal/controller/controller.go | 16 +++++++------- internal/issuer/vault/vault.go | 35 ++++++++++++++++++------------- 4 files changed, 33 insertions(+), 28 deletions(-) diff --git a/config-struct.yaml b/config-struct.yaml index 8ae02fb..200e126 100644 --- a/config-struct.yaml +++ b/config-struct.yaml @@ -11,8 +11,7 @@ issuers: # Описывает список доступных issuers appRole: # блок авторизации в Vault по аппроли name: string # rename $approle_name path: string # rename $approle_path - roleIDLocalPath: string # rename $local_path_to_role_id - secretIDLocalPath: string # rename $local_path_to_secret_id + localPath: string # rename $local_path_to_role_id kv: path: string timeout: string # строка формата "1s", таймаут для любого обращения к issuer diff --git a/internal/config/types.go b/internal/config/types.go index 7e04db6..9dfa360 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -62,10 +62,9 @@ type Bootstrap struct { } type AppRole struct { - Name string `yaml:"name"` - Path string `yaml:"path"` - RoleIDLocalPath string `yaml:"roleIDLocalPath"` - SecretIDLocalPath string `yaml:"secretIDLocalPath"` + Name string `yaml:"name"` + Path string `yaml:"path"` + LocalPath string `yaml:"localPath"` } type KV struct { diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 7ea89e2..54511a0 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -28,7 +28,7 @@ type Resource interface { type controller struct { config Config - vaultConnector func(cfg config.Vault) (Vault, error) + vaultConnector func(name string, cfg config.Vault) (Vault, error) newResource func(vault Vault) Resource resource sync.Map @@ -36,7 +36,7 @@ type controller struct { func New( config Config, - vaultConnector func(cfg config.Vault) (Vault, error), + vaultConnector func(name string, cfg config.Vault) (Vault, error), newResource func(vault Vault) Resource, ) *controller { return &controller{ @@ -77,23 +77,23 @@ func (s *controller) getNewResource() error { return fmt.Errorf("get new configs: %w", err) } - for _, vaultCfg := range cfg.Issuers { + for _, iCfg := range cfg.Issuers { // TODO: что делать если приходит несколько issuer с одинаковыми именами - _, isExist := s.resource.Load(vaultCfg.Name) + _, isExist := s.resource.Load(iCfg.Name) if isExist { zap.L().Warn( "preparing resource", - zap.String("issuer_name", vaultCfg.Name), + zap.String("issuer_name", iCfg.Name), zap.String("step", "connect to issuer"), zap.Error(errors.New("issuer is exist")), ) continue } - vaultConnection, err := s.vaultConnector(vaultCfg.Vault) + vaultConnection, err := s.vaultConnector(iCfg.Name, iCfg.Vault) if err != nil { zap.L().Error( "preparing resource", - zap.String("issuer_name", vaultCfg.Name), + zap.String("issuer_name", iCfg.Name), zap.String("step", "connect to issuer"), zap.Error(err), ) @@ -101,7 +101,7 @@ func (s *controller) getNewResource() error { } r := s.newResource(vaultConnection) - s.resource.Store(vaultCfg.Name, r) + s.resource.Store(iCfg.Name, r) } resources := s.separateResources(cfg.Resource) diff --git a/internal/issuer/vault/vault.go b/internal/issuer/vault/vault.go index cc2975b..55f9acf 100644 --- a/internal/issuer/vault/vault.go +++ b/internal/issuer/vault/vault.go @@ -15,10 +15,11 @@ import ( type vault struct { cli *api.Client + name string kvMountPath string } -func Connect(cfg config.Vault) (controller.Vault, error) { +func Connect(name string, cfg config.Vault) (controller.Vault, error) { client, err := api.NewClient( &api.Config{ Address: cfg.Server, @@ -33,12 +34,13 @@ func Connect(cfg config.Vault) (controller.Vault, error) { client.SetToken(cfg.Auth.Bootstrap.Token) if !cfg.Auth.TLSInsecure { if err = client.CloneConfig().ConfigureTLS(&api.TLSConfig{CACert: cfg.Auth.CABundle}); err != nil { - return nil, fmt.Errorf("configurate tls: %w", err) + return nil, fmt.Errorf("configuring tls: %w", err) } } s := &vault{ cli: client, + name: name, kvMountPath: cfg.KV.Path, } @@ -73,13 +75,15 @@ func Connect(cfg config.Vault) (controller.Vault, error) { } func (s *vault) roleID(appRole config.AppRole) (string, error) { - path := path.Join("auth", appRole.Path, "role", appRole.Name, "role-id") - approle, err := s.Read(path) + vaultPath := path.Join("auth", appRole.Path, "role", appRole.Name, "role-id") + localPath := path.Join(appRole.LocalPath, "role-id-", s.name) + + approle, err := s.Read(vaultPath) if err != nil { - if roleID, rErr := readFromFile(appRole.RoleIDLocalPath); rErr == nil { + if roleID, rErr := readFromFile(localPath); rErr == nil { return string(roleID), nil } - return "", fmt.Errorf("read role_id for path: %s : %w", path, err) + return "", fmt.Errorf("read role_id for path: %s : %w", vaultPath, err) } if approle == nil { return "", fmt.Errorf("no role_id info was returned") @@ -89,20 +93,23 @@ func (s *vault) roleID(appRole config.AppRole) (string, error) { if !ok { return "", fmt.Errorf("not found role_id") } - if err = writeToFile(appRole.RoleIDLocalPath, roleID.(string)); err != nil { - return "", fmt.Errorf("save role id path: %s id: %w", appRole.RoleIDLocalPath, err) + + if err = writeToFile(localPath, roleID.(string)); err != nil { + return "", fmt.Errorf("save role id path: %s id: %w", localPath, err) } return roleID.(string), err } func (s *vault) secretID(appRole config.AppRole) (string, error) { - path := path.Join("auth", appRole.Path, "role", appRole.Name, "secret-id") - approle, err := s.Write(path, nil) + vaultPath := path.Join("auth", appRole.Path, "role", appRole.Name, "secret-id") + localPath := path.Join(appRole.LocalPath, "secret-id-", s.name) + + approle, err := s.Write(vaultPath, nil) if err != nil { - if secretID, rErr := readFromFile(appRole.SecretIDLocalPath); rErr == nil { + if secretID, rErr := readFromFile(localPath); rErr == nil { return string(secretID), nil } - return "", fmt.Errorf("read secrete_id for path: %s : %w", path, err) + return "", fmt.Errorf("read secrete_id for path: %s : %w", vaultPath, err) } if approle == nil { return "", fmt.Errorf("no secrete_id info was returned") @@ -113,8 +120,8 @@ func (s *vault) secretID(appRole config.AppRole) (string, error) { return "", fmt.Errorf("not found secrete_id") } - if err = writeToFile(appRole.SecretIDLocalPath, secretID.(string)); err != nil { - return "", fmt.Errorf("save secret id path: %s id: %w", appRole.SecretIDLocalPath, err) + if err = writeToFile(localPath, secretID.(string)); err != nil { + return "", fmt.Errorf("save secret id path: %s id: %w", localPath, err) } return secretID.(string), err } From da3b950c1ad6b689d1d794bdf803b321ff4dee98 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 12 Sep 2022 17:10:14 +0300 Subject: [PATCH 140/220] refactoring --- cmd/key-keeper/main.go | 2 - config-struct.yaml | 8 +- internal/config/types.go | 22 ++-- internal/controller/controller.go | 54 ++++------ internal/issuer/vault/store.go | 13 --- internal/issuer/vault/vault.go | 30 ++++-- internal/resource/ca-certificate.go | 123 --------------------- internal/resource/certificate.go | 71 ------------ internal/resource/key.go | 46 -------- internal/resource/resource.go | 78 -------------- internal/resource/secret.go | 53 --------- internal/resource/utils.go | 160 ---------------------------- 12 files changed, 60 insertions(+), 600 deletions(-) delete mode 100644 internal/issuer/vault/store.go delete mode 100644 internal/resource/ca-certificate.go delete mode 100644 internal/resource/certificate.go delete mode 100644 internal/resource/key.go delete mode 100644 internal/resource/resource.go delete mode 100644 internal/resource/secret.go delete mode 100644 internal/resource/utils.go diff --git a/cmd/key-keeper/main.go b/cmd/key-keeper/main.go index 08a5e07..84ddcb6 100644 --- a/cmd/key-keeper/main.go +++ b/cmd/key-keeper/main.go @@ -11,7 +11,6 @@ import ( "github.com/fraima/key-keeper/internal/config" "github.com/fraima/key-keeper/internal/controller" "github.com/fraima/key-keeper/internal/issuer/vault" - "github.com/fraima/key-keeper/internal/resource" ) var ( @@ -50,7 +49,6 @@ func main() { cntl := controller.New( cfg, vault.Connect, - resource.Preparing, ) go cntl.RefreshResource() go cntl.Start() diff --git a/config-struct.yaml b/config-struct.yaml index 8ae02fb..640c13e 100644 --- a/config-struct.yaml +++ b/config-struct.yaml @@ -15,6 +15,10 @@ issuers: # Описывает список доступных issuers secretIDLocalPath: string # rename $local_path_to_secret_id kv: path: string + certificate: + role: string # альтернатива блоку csr[*].role + CAPath: string # Путь к сейфу Inermediate CA где будет заказан сертификат + rootCAPath: string # Путь к root CA timeout: string # строка формата "1s", таймаут для любого обращения к issuer certificates: # Описывает список доступных certificates @@ -46,10 +50,6 @@ certificates: # Описывает список доступных certificates interfaces: list of string dnsLookup: list of string ttl: string # на какой промежуток времени заказывается сертификат - vault: - role: string # альтернатива блоку csr[*].role - path: string # Путь к сейфу Inermediate CA где будет заказан сертификат - rootCAPath: string # Путь к root CA hostPath: string # путь, где будет размещен секрет по маске ${hostPathCert}/${certName} renewBefore: string # за сколько до истечения надо перевыпустить trigger: list of string # список bash команд которые применятся после обновления сертификата diff --git a/internal/config/types.go b/internal/config/types.go index 7e04db6..a168ece 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -24,7 +24,6 @@ type Certificate struct { IsCA bool `yaml:"isCa"` CA CA `yaml:"ca"` Spec Spec `yaml:"spec"` - Vault CertVault `yaml:"vault"` HostPath string `yaml:"hostPath"` RenewBefore time.Duration `yaml:"renewBefore"` Trigger []string `yaml:"trigger"` @@ -44,10 +43,11 @@ type Secret struct { } type Vault struct { - Server string `yaml:"server"` - Auth Auth `yaml:"auth"` - KV KV `yaml:"kv"` - Timeout time.Duration `yaml:"timeout"` + Server string `yaml:"server"` + Auth Auth `yaml:"auth"` + Certificate CertVault `yaml:"certificate"` + KV KV `yaml:"kv"` + Timeout time.Duration `yaml:"timeout"` } type Auth struct { @@ -57,6 +57,12 @@ type Auth struct { AppRole AppRole `yaml:"appRole"` } +type CertVault struct { + Role string `yaml:"role"` + CAPath string `yaml:"CAPath"` + RootCAPath string `yaml:"rootCAPath"` +} + type Bootstrap struct { Token string `yaml:"token"` } @@ -101,12 +107,6 @@ type Subject struct { SerialNumber string `yaml:"serialNumber"` } -type CertVault struct { - Role string `yaml:"role"` - Path string `yaml:"path"` - RootCAPath string `yaml:"rootCAPath"` -} - type PrivateKey struct { Algorithm string `yaml:"algorithm"` Encoding string `yaml:"encoding"` diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 7ea89e2..56a3353 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -6,43 +6,34 @@ import ( "sync" "time" - "github.com/fraima/key-keeper/internal/config" "go.uber.org/zap" + + "github.com/fraima/key-keeper/internal/config" ) type Config interface { GetNewConfig() (cfgs config.Config, err error) } -type Vault interface { - Write(path string, data map[string]interface{}) (map[string]interface{}, error) - Read(path string) (map[string]interface{}, error) - Put(secretePath string, data map[string]interface{}) error - Get(secretePath string) (map[string]interface{}, error) -} - -type Resource interface { - Add(r config.Resources) - Check() +type Issuer interface { + AddResource(r config.Resources) + CheckResource() } type controller struct { - config Config - vaultConnector func(cfg config.Vault) (Vault, error) + config Config + issuerConnector func(cfg config.Vault) (Issuer, error) - newResource func(vault Vault) Resource - resource sync.Map + issuer sync.Map } func New( config Config, - vaultConnector func(cfg config.Vault) (Vault, error), - newResource func(vault Vault) Resource, + vaultConnector func(cfg config.Vault) (Issuer, error), ) *controller { return &controller{ - config: config, - vaultConnector: vaultConnector, - newResource: newResource, + config: config, + issuerConnector: vaultConnector, } } @@ -51,8 +42,8 @@ func (s *controller) Start() { t := time.NewTicker(time.Hour) defer t.Stop() for range t.C { - s.resource.Range(func(key, value any) bool { - value.(Resource).Check() + s.issuer.Range(func(key, value any) bool { + value.(Issuer).CheckResource() return true }) } @@ -77,36 +68,35 @@ func (s *controller) getNewResource() error { return fmt.Errorf("get new configs: %w", err) } - for _, vaultCfg := range cfg.Issuers { + for _, iCfg := range cfg.Issuers { // TODO: что делать если приходит несколько issuer с одинаковыми именами - _, isExist := s.resource.Load(vaultCfg.Name) + _, isExist := s.issuer.Load(iCfg.Name) if isExist { zap.L().Warn( "preparing resource", - zap.String("issuer_name", vaultCfg.Name), + zap.String("issuer_name", iCfg.Name), zap.String("step", "connect to issuer"), zap.Error(errors.New("issuer is exist")), ) continue } - vaultConnection, err := s.vaultConnector(vaultCfg.Vault) + conn, err := s.issuerConnector(iCfg.Vault) if err != nil { zap.L().Error( "preparing resource", - zap.String("issuer_name", vaultCfg.Name), + zap.String("issuer_name", iCfg.Name), zap.String("step", "connect to issuer"), zap.Error(err), ) continue } - r := s.newResource(vaultConnection) - s.resource.Store(vaultCfg.Name, r) + s.issuer.Store(iCfg.Name, conn) } resources := s.separateResources(cfg.Resource) - for issuerName, resourceCfg := range resources { - r, isExist := s.resource.Load(issuerName) + for issuerName, rCfg := range resources { + r, isExist := s.issuer.Load(issuerName) if !isExist { zap.L().Warn( "preparing resource", @@ -116,7 +106,7 @@ func (s *controller) getNewResource() error { ) continue } - r.(Resource).Add(resourceCfg) + r.(Issuer).AddResource(rCfg) } return nil diff --git a/internal/issuer/vault/store.go b/internal/issuer/vault/store.go deleted file mode 100644 index 86217a5..0000000 --- a/internal/issuer/vault/store.go +++ /dev/null @@ -1,13 +0,0 @@ -package vault - -import ( - "os" -) - -func readFromFile(path string) ([]byte, error) { - return os.ReadFile(path) -} - -func writeToFile(path, date string) error { - return os.WriteFile(path, []byte(date), 0644) -} diff --git a/internal/issuer/vault/vault.go b/internal/issuer/vault/vault.go index cc2975b..28b04bc 100644 --- a/internal/issuer/vault/vault.go +++ b/internal/issuer/vault/vault.go @@ -14,11 +14,19 @@ import ( ) type vault struct { - cli *api.Client + cli *api.Client + + role string + caPath string + rootCAPath string kvMountPath string + + certificate map[string]config.Certificate + key map[string]config.Key + secret map[string]config.Secret } -func Connect(cfg config.Vault) (controller.Vault, error) { +func Connect(cfg config.Vault) (controller.Issuer, error) { client, err := api.NewClient( &api.Config{ Address: cfg.Server, @@ -38,8 +46,16 @@ func Connect(cfg config.Vault) (controller.Vault, error) { } s := &vault{ - cli: client, + cli: client, + + role: cfg.Certificate.Role, + caPath: cfg.Certificate.CAPath, + rootCAPath: cfg.Certificate.RootCAPath, kvMountPath: cfg.KV.Path, + + certificate: make(map[string]config.Certificate), + key: make(map[string]config.Key), + secret: make(map[string]config.Secret), } roleID, err := s.roleID(cfg.Auth.AppRole) @@ -138,14 +154,14 @@ func (s *vault) Write(path string, data map[string]interface{}) (map[string]inte } // Put in KV. -func (s *vault) Put(secretePath string, data map[string]interface{}) error { - _, err := s.cli.KVv2(s.kvMountPath).Put(context.Background(), secretePath, data) +func (s *vault) Put(kvMountPath, secretePath string, data map[string]interface{}) error { + _, err := s.cli.KVv2(kvMountPath).Put(context.Background(), secretePath, data) return err } // Get from KV. -func (s *vault) Get(secretePath string) (map[string]interface{}, error) { - sec, err := s.cli.KVv2(s.kvMountPath).Get(context.Background(), secretePath) +func (s *vault) Get(kvMountPath, secretePath string) (map[string]interface{}, error) { + sec, err := s.cli.KVv2(kvMountPath).Get(context.Background(), secretePath) if sec != nil { return sec.Data, err } diff --git a/internal/resource/ca-certificate.go b/internal/resource/ca-certificate.go deleted file mode 100644 index c3e74a4..0000000 --- a/internal/resource/ca-certificate.go +++ /dev/null @@ -1,123 +0,0 @@ -package resource - -import ( - "crypto/x509" - "encoding/pem" - "fmt" - "path" - "time" - - "go.uber.org/zap" - - "github.com/fraima/key-keeper/internal/config" -) - -func (s *resource) checkCA(cert config.Certificate) { - var ( - crt, key []byte - err error - ) - - defer func() { - if err := s.storeKeyPair(cert.HostPath, cert.Name, crt, key); err != nil { - zap.L().Error( - "stored intermediate-ca", - zap.Error(err), - ) - } - }() - - crt, key, err = s.readCA(cert.Vault.Path) - if err == nil { - var ca *x509.Certificate - pBlock, _ := pem.Decode(crt) - ca, err = x509.ParseCertificate(pBlock.Bytes) - if err != nil { - err = fmt.Errorf("parse : %w", err) - } - if ca != nil && time.Until(ca.NotAfter) < cert.RenewBefore { - err = fmt.Errorf("expired until(h) %f", time.Until(ca.NotAfter).Hours()) - } - } - - if err != nil { - zap.L().Warn( - "intermediate ca", - zap.String("name", cert.Name), - zap.Error(err), - ) - } else { - return - } - - if cert.CA.Generate { - crt, key, err = s.generateCA(cert) - if err != nil { - zap.L().Error( - "generate intermediate-ca", - zap.String("name", cert.Name), - zap.Error(err), - ) - return - } else { - zap.L().Info( - "intermediate-ca generated", - zap.String("name", cert.Name), - ) - } - } -} - -func (s *resource) generateCA(cert config.Certificate) (crt, key []byte, err error) { - // create intermediate ca - csrData := map[string]interface{}{ - "common_name": fmt.Sprintf("%s Intermediate Authority", cert.Name), - "ttl": cert.Spec.TTL, - } - - keyType := "internal" - if cert.CA.ExportedKey { - keyType = "exported" - } - - vaultPath := path.Join(cert.Vault.Path, "intermediate/generate", keyType) - csr, err := s.vault.Write(vaultPath, csrData) - if err != nil { - err = fmt.Errorf("generate: %w", err) - return - } - - // send the intermediate ca 's CSR to the root CA for signing - icaData := map[string]interface{}{ - "csr": csr["csr"], - "format": "pem_bundle", - "ttl": cert.Spec.TTL, - } - - vaultPath = path.Join(cert.Vault.RootCAPath, "root/sign-intermediate") - ica, err := s.vault.Write(vaultPath, icaData) - if err != nil { - err = fmt.Errorf("send the intermediate ca CSR to the root CA for signing CA: %w", err) - return - } - - // publish the signed certificate back to the intermediate ca - certData := map[string]interface{}{ - "certificate": ica["certificate"], - } - - vaultPath = path.Join(cert.Vault.Path, "intermediate/set-signed") - if _, err = s.vault.Write(vaultPath, certData); err != nil { - err = fmt.Errorf("publish the signed certificate back to the intermediate ca : %w", err) - return - } - - if c, ok := ica["certificate"]; ok { - crt = []byte(c.(string)) - } - if k, ok := csr["private_key"]; ok { - key = []byte(k.(string)) - } - - return -} diff --git a/internal/resource/certificate.go b/internal/resource/certificate.go deleted file mode 100644 index f96ef6d..0000000 --- a/internal/resource/certificate.go +++ /dev/null @@ -1,71 +0,0 @@ -package resource - -import ( - "fmt" - "os" - "os/exec" - "path" - "strings" - "time" - - "go.uber.org/zap" - - "github.com/fraima/key-keeper/internal/config" -) - -func (s *resource) checkCertificate(cfg config.Certificate) { - cert, err := s.readCertificate(cfg.HostPath, cfg.Name) - if cert != nil && time.Until(cert.NotAfter) > cfg.RenewBefore { - return - } - if err != nil && !os.IsNotExist(err) { - zap.L().Error("read csr", zap.String("path", cfg.HostPath), zap.Error(err)) - } - - crt, key, err := s.generateCertificate(cfg) - if err != nil { - zap.L().Error( - "generate csr", - zap.String("name", cfg.Name), - zap.Error(err), - ) - } - - if err = s.storeKeyPair(cfg.HostPath, cfg.Name, crt, key); err != nil { - zap.L().Error( - "store csr", - zap.String("name", cfg.Name), - zap.Error(err), - ) - return - } - - for _, command := range cfg.Trigger { - cmd := strings.Split(command, " ") - err := exec.Command(cmd[0], cmd[1:]...).Run() - zap.L().Error( - "csr trigger", - zap.String("name", cfg.Name), - zap.String("command", command), - zap.Error(err), - ) - } - zap.L().Info("csr generated", zap.String("name", cfg.Name)) -} - -func (s *resource) generateCertificate(cfg config.Certificate) ([]byte, []byte, error) { - csr, key := createCSR(cfg.Spec) - - certData := map[string]interface{}{ - "csr": string(csr), - "ttl": cfg.Spec.TTL, - } - - path := path.Join(cfg.Vault.Path, "sign", cfg.Vault.Role) - cert, err := s.vault.Write(path, certData) - if err != nil { - return nil, nil, fmt.Errorf("generate with path %s : %w", path, err) - } - - return []byte(cert["certificate"].(string)), key, nil -} diff --git a/internal/resource/key.go b/internal/resource/key.go deleted file mode 100644 index 8831c3f..0000000 --- a/internal/resource/key.go +++ /dev/null @@ -1,46 +0,0 @@ -package resource - -import ( - "fmt" - "path" - - "go.uber.org/zap" - - "github.com/fraima/key-keeper/internal/config" -) - -func (s *resource) checkKey(i config.Key) { - private, public, err := s.readKey(i) - if err != nil { - zap.L().Warn( - "read rsa", - zap.String("name", i.Name), - zap.Error(err), - ) - } else { - zap.L().Debug("rsa is read", zap.String("name", i.Name)) - } - - if err := s.storeKey(path.Join(i.HostPath, i.Name), private, public); err != nil { - zap.L().Error( - "store rsa in host", - zap.String("name", i.Name), - zap.String("path", i.HostPath), - zap.Error(err), - ) - return - } - zap.L().Debug("rsa is stored", zap.String("name", i.Name)) -} - -func (s *resource) readKey(i config.Key) (private []byte, public []byte, err error) { - storedRSA, err := s.vault.Get(i.Name) - if err != nil { - err = fmt.Errorf("get from vault_kv : %w", err) - return - } - - // TODO: check - private, public = []byte(storedRSA["private"].(string)), []byte(storedRSA["public"].(string)) - return -} diff --git a/internal/resource/resource.go b/internal/resource/resource.go deleted file mode 100644 index 000e04c..0000000 --- a/internal/resource/resource.go +++ /dev/null @@ -1,78 +0,0 @@ -package resource - -import ( - "sync" - - "github.com/fraima/key-keeper/internal/config" - "github.com/fraima/key-keeper/internal/controller" - "go.uber.org/zap" -) - -type resource struct { - vault controller.Vault - certificate map[string]config.Certificate - key map[string]config.Key - secret map[string]config.Secret -} - -func Preparing( - vault controller.Vault, -) controller.Resource { - return &resource{ - vault: vault, - certificate: make(map[string]config.Certificate), - key: make(map[string]config.Key), - secret: make(map[string]config.Secret), - } -} - -func (s *resource) Check() { - zap.L().Debug("checking") - wg := &sync.WaitGroup{} - - zap.L().Debug("certificate-intermediate-ca") - for _, cert := range s.certificate { - wg.Add(1) - go func(c config.Certificate) { - defer wg.Done() - if c.IsCA { - s.checkCA(c) - return - } - s.checkCertificate(c) - }(cert) - } - wg.Wait() - - zap.L().Debug("keys") - for _, key := range s.key { - wg.Add(1) - go func(k config.Key) { - s.checkKey(k) - }(key) - } - - zap.L().Debug("secrets") - for _, secret := range s.secret { - wg.Add(1) - go func(secret config.Secret) { - s.checkSecret(secret) - }(secret) - } - wg.Wait() - - zap.L().Debug("done") -} - -func (s *resource) Add(r config.Resources) { - for _, cert := range r.Certificates { - s.certificate[cert.Name] = cert - } - for _, key := range r.Keys { - s.key[key.Name] = key - } - for _, secret := range r.Secrets { - s.secret[secret.Name] = secret - } - s.Check() -} diff --git a/internal/resource/secret.go b/internal/resource/secret.go deleted file mode 100644 index 88700fe..0000000 --- a/internal/resource/secret.go +++ /dev/null @@ -1,53 +0,0 @@ -package resource - -import ( - "fmt" - "os" - "path" - - "go.uber.org/zap" - - "github.com/fraima/key-keeper/internal/config" -) - -func (s *resource) checkSecret(i config.Secret) { - secret, err := s.readSecret(i) - if err != nil { - zap.L().Warn( - "read secret", - zap.String("name", i.Name), - zap.Error(err), - ) - } else { - zap.L().Debug("secret is read", zap.String("name", i.Name)) - } - - if err := s.storeSecret(path.Join(i.HostPath, i.Name), secret); err != nil { - zap.L().Error( - "store secrete in host", - zap.String("name", i.Name), - zap.String("path", i.HostPath), - zap.Error(err), - ) - return - } - zap.L().Debug("secret is stored", zap.String("name", i.Name)) -} - -func (s *resource) readSecret(i config.Secret) (secrete []byte, err error) { - storedRSA, err := s.vault.Get(i.Name) - if err != nil { - err = fmt.Errorf("get from vault_kv : %w", err) - return - } - - secrete = []byte(storedRSA[i.Key].(string)) - return -} - -func (s *resource) storeSecret(path string, secret []byte) error { - if err := os.WriteFile(path, secret, 0600); err != nil { - return fmt.Errorf("failed to save secrete with path %s: %w", path, err) - } - return nil -} diff --git a/internal/resource/utils.go b/internal/resource/utils.go deleted file mode 100644 index 1602de8..0000000 --- a/internal/resource/utils.go +++ /dev/null @@ -1,160 +0,0 @@ -package resource - -import ( - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "fmt" - "net" - "os" - "path" - "regexp" - - "github.com/fraima/key-keeper/internal/config" -) - -func (s *resource) storeKey(path string, privare, public []byte) error { - if err := os.WriteFile(path+".pem", privare, 0600); err != nil { - return fmt.Errorf("failed to save privare key with path %s: %w", path, err) - } - - if err := os.WriteFile(path+".pub", public, 0600); err != nil { - return fmt.Errorf("failed to public key file: %w", err) - } - return nil -} - -func (s *resource) storeKeyPair(path string, name string, crt, key []byte) error { - if crt != nil { - if err := os.WriteFile(path+"/"+name+".pem", crt, 0644); err != nil { - return fmt.Errorf("failed to save certificate with path %s: %w", path, err) - } - } - - if key != nil { - if err := os.WriteFile(path+"/"+name+"-key.pem", key, 0600); err != nil { - return fmt.Errorf("failed to save key file: %w", err) - } - } - return nil -} - -func (s *resource) readCertificate(path string, name string) (*x509.Certificate, error) { - crt, err := os.ReadFile(path + "/" + name + ".pem") - if err != nil { - return nil, err - } - - pBlock, _ := pem.Decode(crt) - return x509.ParseCertificate(pBlock.Bytes) -} - -func (s *resource) readCA(vaultPath string) (crt, key []byte, err error) { - vaultPath = path.Join(vaultPath, "cert/ca_chain") - ica, err := s.vault.Read(vaultPath) - if ica != nil { - if c, ok := ica["certificate"]; ok { - crt = []byte(c.(string)) - } - if k, ok := ica["private_key"]; ok { - key = []byte(k.(string)) - } - } - return -} - -func createCSR(spec config.Spec) (crt, key []byte) { - pk, _ := rsa.GenerateKey(rand.Reader, spec.PrivateKey.Size) - - template := x509.CertificateRequest{ - Subject: pkix.Name{ - CommonName: spec.Subject.CommonName, - Country: spec.Subject.Country, - Locality: spec.Subject.Locality, - Organization: spec.Subject.Organization, - OrganizationalUnit: spec.Subject.OrganizationalUnit, - Province: spec.Subject.Province, - PostalCode: spec.Subject.PostalCode, - StreetAddress: spec.Subject.StreetAddress, - SerialNumber: spec.Subject.SerialNumber, - }, - IPAddresses: getIPAddresses(spec.IPAddresses), - DNSNames: spec.Hostnames, - SignatureAlgorithm: x509.SHA256WithRSA, - } - - csr, _ := x509.CreateCertificateRequest(rand.Reader, &template, pk) - - //pem encoding of certificate - return pem.EncodeToMemory( - &pem.Block{ - Type: "CERTIFICATE REQUEST", - Bytes: csr, - }, - ), pem.EncodeToMemory( - &pem.Block{ - Type: "RSA PRIVATE KEY", - Bytes: x509.MarshalPKCS1PrivateKey(pk), - }, - ) - -} - -func getIPAddresses(cfg config.IPAddresses) []net.IP { - ipAddresses := make(map[string]net.IP) - - for _, ip := range cfg.Static { - netIP := net.ParseIP(ip) - if netIP.To4() != nil { - ipAddresses[ip] = netIP - } - } - - ifaces, _ := net.Interfaces() - // TODO: handle err - for _, i := range ifaces { - if inSlice(i.Name, cfg.Interfaces) { - addrs, _ := i.Addrs() - // TODO: handle err - for _, addr := range addrs { - var ip net.IP - switch v := addr.(type) { - case *net.IPNet: - ip = v.IP - case *net.IPAddr: - ip = v.IP - } - - if ip.To4() != nil { - ipAddresses[ip.String()] = ip - } - } - } - } - - for _, h := range cfg.DNSLookup { - ips, _ := net.LookupIP(h) - for _, ip := range ips { - if ip.To4() != nil { - ipAddresses[ip.String()] = ip - } - } - } - - r := make([]net.IP, 0, len(ipAddresses)) - for _, ip := range ipAddresses { - r = append(r, ip) - } - return r -} - -func inSlice(str string, sl []string) bool { - for _, s := range sl { - if regexp.MustCompile(s).MatchString(str) { - return true - } - } - return false -} From 81613aeec8fd46917a7e97bafbea54958364b7d4 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 12 Sep 2022 17:10:27 +0300 Subject: [PATCH 141/220] refactoring --- internal/issuer/vault/ca-certificate.go | 134 ++++++++++++++++ internal/issuer/vault/certificate.go | 202 ++++++++++++++++++++++++ internal/issuer/vault/key.go | 64 ++++++++ internal/issuer/vault/resource.go | 60 +++++++ internal/issuer/vault/secret.go | 55 +++++++ internal/issuer/vault/utils.go | 41 +++++ 6 files changed, 556 insertions(+) create mode 100644 internal/issuer/vault/ca-certificate.go create mode 100644 internal/issuer/vault/certificate.go create mode 100644 internal/issuer/vault/key.go create mode 100644 internal/issuer/vault/resource.go create mode 100644 internal/issuer/vault/secret.go create mode 100644 internal/issuer/vault/utils.go diff --git a/internal/issuer/vault/ca-certificate.go b/internal/issuer/vault/ca-certificate.go new file mode 100644 index 0000000..e5a1869 --- /dev/null +++ b/internal/issuer/vault/ca-certificate.go @@ -0,0 +1,134 @@ +package vault + +import ( + "crypto/x509" + "encoding/pem" + "fmt" + "path" + "time" + + "go.uber.org/zap" + + "github.com/fraima/key-keeper/internal/config" +) + +func (s *vault) checkCA(cert config.Certificate) { + var ( + crt, key []byte + err error + ) + + defer func() { + if err := storeKeyPair(cert.HostPath, cert.Name, crt, key); err != nil { + zap.L().Error( + "stored intermediate-ca", + zap.Error(err), + ) + } + }() + + crt, key, err = s.readCA(s.caPath) + if err == nil { + var ca *x509.Certificate + pBlock, _ := pem.Decode(crt) + ca, err = x509.ParseCertificate(pBlock.Bytes) + if err != nil { + err = fmt.Errorf("parse : %w", err) + } + if ca != nil && time.Until(ca.NotAfter) < cert.RenewBefore { + err = fmt.Errorf("expired until(h) %f", time.Until(ca.NotAfter).Hours()) + } + } + + if err != nil { + zap.L().Warn( + "intermediate ca", + zap.String("name", cert.Name), + zap.Error(err), + ) + } else { + return + } + + if cert.CA.Generate { + crt, key, err = s.generateCA(cert) + if err != nil { + zap.L().Error( + "generate intermediate-ca", + zap.String("name", cert.Name), + zap.Error(err), + ) + return + } else { + zap.L().Info( + "intermediate-ca generated", + zap.String("name", cert.Name), + ) + } + } +} + +func (s *vault) generateCA(cert config.Certificate) (crt, key []byte, err error) { + csrData := map[string]interface{}{ + "common_name": fmt.Sprintf("%s Intermediate Authority", cert.Name), + "ttl": cert.Spec.TTL, + } + + keyType := "internal" + if cert.CA.ExportedKey { + keyType = "exported" + } + + vaultPath := path.Join(s.caPath, "intermediate/generate", keyType) + csr, err := s.Write(vaultPath, csrData) + if err != nil { + err = fmt.Errorf("generate: %w", err) + return + } + + // send the intermediate ca 's CSR to the root CA for signing + icaData := map[string]interface{}{ + "csr": csr["csr"], + "format": "pem_bundle", + "ttl": cert.Spec.TTL, + } + + vaultPath = path.Join(s.rootCAPath, "root/sign-intermediate") + ica, err := s.Write(vaultPath, icaData) + if err != nil { + err = fmt.Errorf("send the intermediate ca CSR to the root CA for signing CA: %w", err) + return + } + + certData := map[string]interface{}{ + "certificate": ica["certificate"], + } + + vaultPath = path.Join(s.caPath, "intermediate/set-signed") + if _, err = s.Write(vaultPath, certData); err != nil { + err = fmt.Errorf("publish the signed certificate back to the intermediate ca : %w", err) + return + } + + if c, ok := ica["certificate"]; ok { + crt = []byte(c.(string)) + } + if k, ok := csr["private_key"]; ok { + key = []byte(k.(string)) + } + return +} + +func (s *vault) readCA(vaultPath string) (crt, key []byte, err error) { + vaultPath = path.Join(vaultPath, "cert/ca_chain") + ica, err := s.Read(vaultPath) + if ica != nil { + if c, ok := ica["certificate"]; ok { + crt = []byte(c.(string)) + } + if k, ok := ica["private_key"]; ok { + key = []byte(k.(string)) + } + } + return +} diff --git a/internal/issuer/vault/certificate.go b/internal/issuer/vault/certificate.go new file mode 100644 index 0000000..e2e33af --- /dev/null +++ b/internal/issuer/vault/certificate.go @@ -0,0 +1,202 @@ +package vault + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "errors" + "fmt" + "net" + "os" + "os/exec" + "path" + "regexp" + "strings" + "time" + + "go.uber.org/zap" + + "github.com/fraima/key-keeper/internal/config" +) + +func (s *vault) checkCertificate(certCfg config.Certificate) { + cert, err := readCertificate(certCfg.HostPath, certCfg.Name) + if cert != nil && time.Until(cert.NotAfter) > certCfg.RenewBefore { + return + } + if err != nil && !os.IsNotExist(err) { + zap.L().Error("read certificate", zap.String("path", certCfg.HostPath), zap.Error(err)) + } + + crt, key, err := s.generateCertificate(certCfg.Spec) + if err != nil { + zap.L().Error( + "generate certificate", + zap.String("name", certCfg.Name), + zap.Error(err), + ) + } + + if err = storeKeyPair(certCfg.HostPath, certCfg.Name, crt, key); err != nil { + zap.L().Error( + "store certificate", + zap.String("name", certCfg.Name), + zap.Error(err), + ) + return + } + + for _, command := range certCfg.Trigger { + cmd := strings.Split(command, " ") + err := exec.Command(cmd[0], cmd[1:]...).Run() + zap.L().Error( + "certificate trigger", + zap.String("name", certCfg.Name), + zap.String("command", command), + zap.Error(err), + ) + } + zap.L().Info("certificate generated", zap.String("name", certCfg.Name)) +} + +func (s *vault) generateCertificate(certSpec config.Spec) ([]byte, []byte, error) { + csr, key, err := createCSR(certSpec) + if err != nil { + return nil, nil, fmt.Errorf("create csr: %w", err) + } + + certData := map[string]interface{}{ + "csr": string(csr), + "ttl": certSpec.TTL, + } + + vaultPath := path.Join(s.caPath, "sign", s.role) + cert, err := s.Write(vaultPath, certData) + if err != nil { + return nil, nil, fmt.Errorf("generate with vault path %s : %w", vaultPath, err) + } + + if crt, ok := cert["certificate"]; ok { + return []byte(crt.(string)), key, nil + } + + return nil, nil, fmt.Errorf("certificate block not found") +} + +func createCSR(spec config.Spec) (crt, key []byte, err error) { + pk, err := rsa.GenerateKey(rand.Reader, spec.PrivateKey.Size) + if err != nil { + err = fmt.Errorf("generate key: %w", err) + return + } + + ips, err := getIPAddresses(spec.IPAddresses) + if err != nil { + err = fmt.Errorf("get ip addresses: %w", err) + return + } + template := x509.CertificateRequest{ + Subject: pkix.Name{ + CommonName: spec.Subject.CommonName, + Country: spec.Subject.Country, + Locality: spec.Subject.Locality, + Organization: spec.Subject.Organization, + OrganizationalUnit: spec.Subject.OrganizationalUnit, + Province: spec.Subject.Province, + PostalCode: spec.Subject.PostalCode, + StreetAddress: spec.Subject.StreetAddress, + SerialNumber: spec.Subject.SerialNumber, + }, + IPAddresses: ips, + DNSNames: spec.Hostnames, + SignatureAlgorithm: x509.SHA256WithRSA, + } + + csr, err := x509.CreateCertificateRequest(rand.Reader, &template, pk) + if err != nil { + err = fmt.Errorf("create certificate request: %w", err) + return + } + + crt = pem.EncodeToMemory( + &pem.Block{ + Type: "CERTIFICATE REQUEST", + Bytes: csr, + }, + ) + key = pem.EncodeToMemory( + &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(pk), + }, + ) + return +} + +func getIPAddresses(cfg config.IPAddresses) ([]net.IP, error) { + ipAddresses := make(map[string]net.IP) + + for _, ip := range cfg.Static { + netIP := net.ParseIP(ip) + if netIP.To4() != nil { + ipAddresses[ip] = netIP + } + } + + ifaces, err := net.Interfaces() + if err != nil { + return nil, errors.New("get interfaces") + } + + for _, i := range ifaces { + if inSlice(i.Name, cfg.Interfaces) { + addrs, err := i.Addrs() + if err != nil { + return nil, fmt.Errorf("get interface %s addresses", i.Name) + } + + for _, addr := range addrs { + var ip net.IP + switch v := addr.(type) { + case *net.IPNet: + ip = v.IP + case *net.IPAddr: + ip = v.IP + } + + if ip.To4() != nil { + ipAddresses[ip.String()] = ip + } + } + } + } + + for _, h := range cfg.DNSLookup { + ips, err := net.LookupIP(h) + if err != nil { + return nil, fmt.Errorf("lookup ip for %s ", h) + } + for _, ip := range ips { + if ip.To4() != nil { + ipAddresses[ip.String()] = ip + } + } + } + + r := make([]net.IP, 0, len(ipAddresses)) + for _, ip := range ipAddresses { + r = append(r, ip) + } + return r, nil +} + +func inSlice(str string, sl []string) bool { + for _, s := range sl { + if regexp.MustCompile(s).MatchString(str) { + return true + } + } + return false +} diff --git a/internal/issuer/vault/key.go b/internal/issuer/vault/key.go new file mode 100644 index 0000000..6a280fc --- /dev/null +++ b/internal/issuer/vault/key.go @@ -0,0 +1,64 @@ +package vault + +import ( + "fmt" + "os" + "path" + + "go.uber.org/zap" + + "github.com/fraima/key-keeper/internal/config" +) + +func (s *vault) checkKeyPair(i config.Key) { + private, public, err := s.readKey(i) + if err != nil { + zap.L().Warn( + "read key", + zap.String("name", i.Name), + zap.Error(err), + ) + return + } else { + zap.L().Debug("key is read", zap.String("name", i.Name)) + } + + if err := s.saveKeyOnHost(path.Join(i.HostPath, i.Name), private, public); err != nil { + zap.L().Error( + "save key in host", + zap.String("name", i.Name), + zap.String("path", i.HostPath), + zap.Error(err), + ) + return + } + zap.L().Debug("key is save in host", zap.String("name", i.Name)) +} + +func (s *vault) readKey(i config.Key) (private []byte, public []byte, err error) { + storedKye, err := s.Get(s.kvMountPath,i.Name) + if err != nil { + err = fmt.Errorf("get from vault_kv : %w", err) + return + } + + if c, ok := storedKye["private"]; ok { + private = []byte(c.(string)) + } + if k, ok := storedKye["public"]; ok { + public = []byte(k.(string)) + } + + return +} + +func (s *vault) saveKeyOnHost(path string, private, public []byte) error { + if err := os.WriteFile(path+".pem", private, 0600); err != nil { + return fmt.Errorf("failed to save private key with path %s: %w", path, err) + } + + if err := os.WriteFile(path+".pub", public, 0600); err != nil { + return fmt.Errorf("failed to public key file: %w", err) + } + return nil +} diff --git a/internal/issuer/vault/resource.go b/internal/issuer/vault/resource.go new file mode 100644 index 0000000..59b5c06 --- /dev/null +++ b/internal/issuer/vault/resource.go @@ -0,0 +1,60 @@ +package vault + +import ( + "sync" + + "go.uber.org/zap" + + "github.com/fraima/key-keeper/internal/config" +) + +func (s *vault) AddResource(r config.Resources) { + for _, cert := range r.Certificates { + s.certificate[cert.Name] = cert + } + for _, key := range r.Keys { + s.key[key.Name] = key + } + for _, secret := range r.Secrets { + s.secret[secret.Name] = secret + } + s.CheckResource() +} + +func (s *vault) CheckResource() { + zap.L().Debug("checking") + wg := &sync.WaitGroup{} + + zap.L().Debug("certificate-intermediate-ca") + for _, cert := range s.certificate { + wg.Add(1) + go func(c config.Certificate) { + defer wg.Done() + if c.IsCA { + s.checkCA(c) + return + } + s.checkCertificate(c) + }(cert) + } + wg.Wait() + + zap.L().Debug("keys") + for _, key := range s.key { + wg.Add(1) + go func(k config.Key) { + s.checkKeyPair(k) + }(key) + } + + zap.L().Debug("secrets") + for _, secret := range s.secret { + wg.Add(1) + go func(secret config.Secret) { + s.checkSecret(secret) + }(secret) + } + wg.Wait() + + zap.L().Debug("done") +} diff --git a/internal/issuer/vault/secret.go b/internal/issuer/vault/secret.go new file mode 100644 index 0000000..29d57ef --- /dev/null +++ b/internal/issuer/vault/secret.go @@ -0,0 +1,55 @@ +package vault + +import ( + "fmt" + "os" + "path" + + "go.uber.org/zap" + + "github.com/fraima/key-keeper/internal/config" +) + +func (s *vault) checkSecret(i config.Secret) { + secret, err := s.readSecret(i) + if err != nil { + zap.L().Warn( + "read secret", + zap.String("name", i.Name), + zap.Error(err), + ) + } else { + zap.L().Debug("secret is read", zap.String("name", i.Name)) + } + + if err := s.storeSecret(path.Join(i.HostPath, i.Name), secret); err != nil { + zap.L().Error( + "store secrete in host", + zap.String("name", i.Name), + zap.String("path", i.HostPath), + zap.Error(err), + ) + return + } + zap.L().Debug("secret is stored", zap.String("name", i.Name)) +} + +func (s *vault) readSecret(i config.Secret) (secrete []byte, err error) { + storedSecrete, err := s.Get(s.kvMountPath, i.Name) + if err != nil { + err = fmt.Errorf("get from vault_kv : %w", err) + return + } + + if data, ok := storedSecrete[i.Key]; ok { + secrete = []byte(data.(string)) + } + return +} + +func (s *vault) storeSecret(path string, secret []byte) error { + if err := os.WriteFile(path, secret, 0600); err != nil { + return fmt.Errorf("failed to save secrete with path %s: %w", path, err) + } + return nil +} diff --git a/internal/issuer/vault/utils.go b/internal/issuer/vault/utils.go new file mode 100644 index 0000000..5875290 --- /dev/null +++ b/internal/issuer/vault/utils.go @@ -0,0 +1,41 @@ +package vault + +import ( + "crypto/x509" + "encoding/pem" + "fmt" + "os" +) + +func storeKeyPair(path string, name string, crt, key []byte) error { + if crt != nil { + if err := os.WriteFile(path+"/"+name+".pem", crt, 0644); err != nil { + return fmt.Errorf("failed to save certificate with path %s: %w", path, err) + } + } + + if key != nil { + if err := os.WriteFile(path+"/"+name+"-key.pem", key, 0600); err != nil { + return fmt.Errorf("failed to save key file: %w", err) + } + } + return nil +} + +func readCertificate(path string, name string) (*x509.Certificate, error) { + crt, err := os.ReadFile(path + "/" + name + ".pem") + if err != nil { + return nil, err + } + + pBlock, _ := pem.Decode(crt) + return x509.ParseCertificate(pBlock.Bytes) +} + +func readFromFile(path string) ([]byte, error) { + return os.ReadFile(path) +} + +func writeToFile(path, date string) error { + return os.WriteFile(path, []byte(date), 0644) +} From 4b382a2a4c8bf6a15aadaa0e010e9064d02f2cf7 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 15 Sep 2022 15:50:51 +0300 Subject: [PATCH 142/220] ref --- internal/controller/controller.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 56a3353..dbef635 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -12,24 +12,24 @@ import ( ) type Config interface { - GetNewConfig() (cfgs config.Config, err error) + GetNewConfig() (config.Config, error) } type Issuer interface { - AddResource(r config.Resources) + AddResource(config.Resources) CheckResource() } type controller struct { config Config - issuerConnector func(cfg config.Vault) (Issuer, error) + issuerConnector func(config.Vault) (Issuer, error) issuer sync.Map } func New( config Config, - vaultConnector func(cfg config.Vault) (Issuer, error), + vaultConnector func(config.Vault) (Issuer, error), ) *controller { return &controller{ config: config, From 65951b4fc519ba38532bbbc44c9bb3afe1a26d7f Mon Sep 17 00:00:00 2001 From: irbgeo Date: Fri, 16 Sep 2022 13:17:32 +0300 Subject: [PATCH 143/220] update --- internal/issuer/vault/certificate.go | 1 + internal/issuer/vault/key.go | 5 ++--- internal/issuer/vault/secret.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/issuer/vault/certificate.go b/internal/issuer/vault/certificate.go index e2e33af..cef925c 100644 --- a/internal/issuer/vault/certificate.go +++ b/internal/issuer/vault/certificate.go @@ -97,6 +97,7 @@ func createCSR(spec config.Spec) (crt, key []byte, err error) { err = fmt.Errorf("get ip addresses: %w", err) return } + template := x509.CertificateRequest{ Subject: pkix.Name{ CommonName: spec.Subject.CommonName, diff --git a/internal/issuer/vault/key.go b/internal/issuer/vault/key.go index 6a280fc..d4d3db3 100644 --- a/internal/issuer/vault/key.go +++ b/internal/issuer/vault/key.go @@ -3,7 +3,6 @@ package vault import ( "fmt" "os" - "path" "go.uber.org/zap" @@ -23,7 +22,7 @@ func (s *vault) checkKeyPair(i config.Key) { zap.L().Debug("key is read", zap.String("name", i.Name)) } - if err := s.saveKeyOnHost(path.Join(i.HostPath, i.Name), private, public); err != nil { + if err := s.saveKeyOnHost(i.HostPath, private, public); err != nil { zap.L().Error( "save key in host", zap.String("name", i.Name), @@ -36,7 +35,7 @@ func (s *vault) checkKeyPair(i config.Key) { } func (s *vault) readKey(i config.Key) (private []byte, public []byte, err error) { - storedKye, err := s.Get(s.kvMountPath,i.Name) + storedKye, err := s.Get(s.kvMountPath, i.Name) if err != nil { err = fmt.Errorf("get from vault_kv : %w", err) return diff --git a/internal/issuer/vault/secret.go b/internal/issuer/vault/secret.go index 29d57ef..cc4dc94 100644 --- a/internal/issuer/vault/secret.go +++ b/internal/issuer/vault/secret.go @@ -22,7 +22,7 @@ func (s *vault) checkSecret(i config.Secret) { zap.L().Debug("secret is read", zap.String("name", i.Name)) } - if err := s.storeSecret(path.Join(i.HostPath, i.Name), secret); err != nil { + if err := s.storeSecret(i.HostPath, secret); err != nil { zap.L().Error( "store secrete in host", zap.String("name", i.Name), From 9c3240e117de642e5ca2312ba9d40d5c499c54a5 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 19 Sep 2022 13:32:29 +0300 Subject: [PATCH 144/220] FD-15-paths --- internal/issuer/vault/secret.go | 1 - internal/issuer/vault/utils.go | 7 +++++++ internal/issuer/vault/vault.go | 35 ++++++++++++++++++++------------- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/internal/issuer/vault/secret.go b/internal/issuer/vault/secret.go index cc4dc94..f69faac 100644 --- a/internal/issuer/vault/secret.go +++ b/internal/issuer/vault/secret.go @@ -3,7 +3,6 @@ package vault import ( "fmt" "os" - "path" "go.uber.org/zap" diff --git a/internal/issuer/vault/utils.go b/internal/issuer/vault/utils.go index 5875290..64ecd1b 100644 --- a/internal/issuer/vault/utils.go +++ b/internal/issuer/vault/utils.go @@ -8,6 +8,10 @@ import ( ) func storeKeyPair(path string, name string, crt, key []byte) error { + if err := os.MkdirAll(path, 0600); err != nil { + return fmt.Errorf("mkdir all %s : %w", path, err) + } + if crt != nil { if err := os.WriteFile(path+"/"+name+".pem", crt, 0644); err != nil { return fmt.Errorf("failed to save certificate with path %s: %w", path, err) @@ -37,5 +41,8 @@ func readFromFile(path string) ([]byte, error) { } func writeToFile(path, date string) error { + if err := os.MkdirAll(path, 0600); err != nil { + return fmt.Errorf("mkdir all %s : %w", path, err) + } return os.WriteFile(path, []byte(date), 0644) } diff --git a/internal/issuer/vault/vault.go b/internal/issuer/vault/vault.go index aed179d..aa48321 100644 --- a/internal/issuer/vault/vault.go +++ b/internal/issuer/vault/vault.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/http" + "os" "path" "github.com/hashicorp/vault/api" @@ -89,14 +90,17 @@ func Connect(name string, cfg config.Vault) (controller.Issuer, error) { } func (s *vault) roleID(name string, appRole config.AppRole) (string, error) { - vaultPath := path.Join("auth", appRole.Path, "role", appRole.Name, "role-id") - localPath := path.Join(appRole.LocalPath, "role-id-"+name) + if roleID, rErr := readFromFile(appRole.LocalPath); rErr == nil { + return string(roleID), nil + } + + if err := os.MkdirAll(appRole.LocalPath, 0600); err != nil { + return "", fmt.Errorf("mkdir all %s : %w", appRole.LocalPath, err) + } + vaultPath := path.Join("auth", appRole.Path, "role", appRole.Name, "role-id") approle, err := s.Read(vaultPath) if err != nil { - if roleID, rErr := readFromFile(localPath); rErr == nil { - return string(roleID), nil - } return "", fmt.Errorf("read role_id for path: %s : %w", vaultPath, err) } if approle == nil { @@ -108,21 +112,24 @@ func (s *vault) roleID(name string, appRole config.AppRole) (string, error) { return "", fmt.Errorf("not found role_id") } - if err = writeToFile(localPath, roleID.(string)); err != nil { - return "", fmt.Errorf("save role id path: %s id: %w", localPath, err) + if err = writeToFile(appRole.LocalPath, roleID.(string)); err != nil { + return "", fmt.Errorf("save role id path: %s id: %w", appRole.LocalPath, err) } return roleID.(string), err } func (s *vault) secretID(name string, appRole config.AppRole) (string, error) { - vaultPath := path.Join("auth", appRole.Path, "role", appRole.Name, "secret-id") - localPath := path.Join(appRole.LocalPath, "secret-id-"+name) + if secretID, rErr := readFromFile(appRole.LocalPath); rErr == nil { + return string(secretID), nil + } + + if err := os.MkdirAll(appRole.LocalPath, 0600); err != nil { + return "", fmt.Errorf("mkdir all %s : %w", appRole.LocalPath, err) + } + vaultPath := path.Join("auth", appRole.Path, "role", appRole.Name, "secret-id") approle, err := s.Write(vaultPath, nil) if err != nil { - if secretID, rErr := readFromFile(localPath); rErr == nil { - return string(secretID), nil - } return "", fmt.Errorf("read secrete_id for path: %s : %w", vaultPath, err) } if approle == nil { @@ -134,8 +141,8 @@ func (s *vault) secretID(name string, appRole config.AppRole) (string, error) { return "", fmt.Errorf("not found secrete_id") } - if err = writeToFile(localPath, secretID.(string)); err != nil { - return "", fmt.Errorf("save secret id path: %s id: %w", localPath, err) + if err = writeToFile(appRole.LocalPath, secretID.(string)); err != nil { + return "", fmt.Errorf("save secret id path: %s id: %w", appRole.LocalPath, err) } return secretID.(string), err } From 6eb0c19ef21d47f189d54f49e35450957c6132a7 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 19 Sep 2022 13:33:45 +0300 Subject: [PATCH 145/220] update --- internal/issuer/vault/vault.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/internal/issuer/vault/vault.go b/internal/issuer/vault/vault.go index aa48321..d6bf79f 100644 --- a/internal/issuer/vault/vault.go +++ b/internal/issuer/vault/vault.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "net/http" - "os" "path" "github.com/hashicorp/vault/api" @@ -94,10 +93,6 @@ func (s *vault) roleID(name string, appRole config.AppRole) (string, error) { return string(roleID), nil } - if err := os.MkdirAll(appRole.LocalPath, 0600); err != nil { - return "", fmt.Errorf("mkdir all %s : %w", appRole.LocalPath, err) - } - vaultPath := path.Join("auth", appRole.Path, "role", appRole.Name, "role-id") approle, err := s.Read(vaultPath) if err != nil { @@ -123,10 +118,6 @@ func (s *vault) secretID(name string, appRole config.AppRole) (string, error) { return string(secretID), nil } - if err := os.MkdirAll(appRole.LocalPath, 0600); err != nil { - return "", fmt.Errorf("mkdir all %s : %w", appRole.LocalPath, err) - } - vaultPath := path.Join("auth", appRole.Path, "role", appRole.Name, "secret-id") approle, err := s.Write(vaultPath, nil) if err != nil { From f2308dc942abb43155c5db11ac1a0c59f1d4b04b Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 19 Sep 2022 13:36:22 +0300 Subject: [PATCH 146/220] up dir permission --- internal/issuer/vault/utils.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/issuer/vault/utils.go b/internal/issuer/vault/utils.go index 64ecd1b..4d681a5 100644 --- a/internal/issuer/vault/utils.go +++ b/internal/issuer/vault/utils.go @@ -8,7 +8,7 @@ import ( ) func storeKeyPair(path string, name string, crt, key []byte) error { - if err := os.MkdirAll(path, 0600); err != nil { + if err := os.MkdirAll(path, 0644); err != nil { return fmt.Errorf("mkdir all %s : %w", path, err) } @@ -41,7 +41,7 @@ func readFromFile(path string) ([]byte, error) { } func writeToFile(path, date string) error { - if err := os.MkdirAll(path, 0600); err != nil { + if err := os.MkdirAll(path, 0644); err != nil { return fmt.Errorf("mkdir all %s : %w", path, err) } return os.WriteFile(path, []byte(date), 0644) From 19f35f32ce2b47e2aa581b7ca5ccea754cc45677 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 19 Sep 2022 13:49:00 +0300 Subject: [PATCH 147/220] update struct path --- config-struct.yaml | 3 ++- internal/config/types.go | 7 ++++--- internal/issuer/vault/vault.go | 12 ++++++------ 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/config-struct.yaml b/config-struct.yaml index 4b04cc6..dde404a 100644 --- a/config-struct.yaml +++ b/config-struct.yaml @@ -11,7 +11,8 @@ issuers: # Описывает список доступных issuers appRole: # блок авторизации в Vault по аппроли name: string # rename $approle_name path: string # rename $approle_path - localPath: string # rename $local_path_to_role_id + roleIDLocalPath: string # rename $local_path_to_role_id + secretIDLocalPath: string kv: path: string certificate: diff --git a/internal/config/types.go b/internal/config/types.go index 74ea270..dc91bde 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -68,9 +68,10 @@ type Bootstrap struct { } type AppRole struct { - Name string `yaml:"name"` - Path string `yaml:"path"` - LocalPath string `yaml:"localPath"` + Name string `yaml:"name"` + Path string `yaml:"path"` + RoleIDLocalPath string `yaml:"roleIDLocalPath"` + SecretIDLocalPath string `yaml:"secreteIDLocalPath"` } type KV struct { diff --git a/internal/issuer/vault/vault.go b/internal/issuer/vault/vault.go index d6bf79f..bb32745 100644 --- a/internal/issuer/vault/vault.go +++ b/internal/issuer/vault/vault.go @@ -89,7 +89,7 @@ func Connect(name string, cfg config.Vault) (controller.Issuer, error) { } func (s *vault) roleID(name string, appRole config.AppRole) (string, error) { - if roleID, rErr := readFromFile(appRole.LocalPath); rErr == nil { + if roleID, rErr := readFromFile(appRole.RoleIDLocalPath); rErr == nil { return string(roleID), nil } @@ -107,14 +107,14 @@ func (s *vault) roleID(name string, appRole config.AppRole) (string, error) { return "", fmt.Errorf("not found role_id") } - if err = writeToFile(appRole.LocalPath, roleID.(string)); err != nil { - return "", fmt.Errorf("save role id path: %s id: %w", appRole.LocalPath, err) + if err = writeToFile(appRole.RoleIDLocalPath, roleID.(string)); err != nil { + return "", fmt.Errorf("save role id path: %s id: %w", appRole.RoleIDLocalPath, err) } return roleID.(string), err } func (s *vault) secretID(name string, appRole config.AppRole) (string, error) { - if secretID, rErr := readFromFile(appRole.LocalPath); rErr == nil { + if secretID, rErr := readFromFile(appRole.SecretIDLocalPath); rErr == nil { return string(secretID), nil } @@ -132,8 +132,8 @@ func (s *vault) secretID(name string, appRole config.AppRole) (string, error) { return "", fmt.Errorf("not found secrete_id") } - if err = writeToFile(appRole.LocalPath, secretID.(string)); err != nil { - return "", fmt.Errorf("save secret id path: %s id: %w", appRole.LocalPath, err) + if err = writeToFile(appRole.RoleIDLocalPath, secretID.(string)); err != nil { + return "", fmt.Errorf("save secret id path: %s id: %w", appRole.RoleIDLocalPath, err) } return secretID.(string), err } From 82e8e867260f9abe596350b3ce5cb2e6610584a5 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 19 Sep 2022 13:56:30 +0300 Subject: [PATCH 148/220] up --- go.mod | 2 +- internal/config/config.go | 3 +- internal/config/types.go | 2 +- internal/issuer/vault/utils.go | 10 +- test.yaml | 618 --------------------------------- 5 files changed, 9 insertions(+), 626 deletions(-) delete mode 100644 test.yaml diff --git a/go.mod b/go.mod index cfda956..50a07f0 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/fraima/key-keeper -go 1.18 +go 1.19 require ( github.com/hashicorp/vault/api v1.7.1 diff --git a/internal/config/config.go b/internal/config/config.go index c159524..520f5bb 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1,7 +1,6 @@ package config import ( - "io/ioutil" "os" "path/filepath" "regexp" @@ -39,7 +38,7 @@ func (s *config) GetNewConfig() (newCfg Config, err error) { } for _, path := range list { - data, err := ioutil.ReadFile(path) + data, err := os.ReadFile(path) if err != nil { zap.L().Error("read config file", zap.String("path", path), zap.Error(err)) continue diff --git a/internal/config/types.go b/internal/config/types.go index dc91bde..a168ece 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -71,7 +71,7 @@ type AppRole struct { Name string `yaml:"name"` Path string `yaml:"path"` RoleIDLocalPath string `yaml:"roleIDLocalPath"` - SecretIDLocalPath string `yaml:"secreteIDLocalPath"` + SecretIDLocalPath string `yaml:"secretIDLocalPath"` } type KV struct { diff --git a/internal/issuer/vault/utils.go b/internal/issuer/vault/utils.go index 4d681a5..fac0fe1 100644 --- a/internal/issuer/vault/utils.go +++ b/internal/issuer/vault/utils.go @@ -5,6 +5,7 @@ import ( "encoding/pem" "fmt" "os" + "path" ) func storeKeyPair(path string, name string, crt, key []byte) error { @@ -40,9 +41,10 @@ func readFromFile(path string) ([]byte, error) { return os.ReadFile(path) } -func writeToFile(path, date string) error { - if err := os.MkdirAll(path, 0644); err != nil { - return fmt.Errorf("mkdir all %s : %w", path, err) +func writeToFile(filepath, date string) error { + dir := path.Dir(filepath) + if err := os.MkdirAll(dir, 0644); err != nil { + return fmt.Errorf("mkdir all %s : %w", dir, err) } - return os.WriteFile(path, []byte(date), 0644) + return os.WriteFile(filepath, []byte(date), 0644) } diff --git a/test.yaml b/test.yaml deleted file mode 100644 index e4b3de7..0000000 --- a/test.yaml +++ /dev/null @@ -1,618 +0,0 @@ ---- -issuers: - - name: front-proxy-ca - vault: - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - localPath: /tmp/kubernetes/pki/vault/ - certificate: - role: "" - CAPath: "clusters/cluster-1/pki/front-proxy" - rootCAPath: "clusters/cluster-1/pki/root" - timeout: 15s - - - name: front-proxy-client - vault: - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - localPath: /tmp/kubernetes/pki/vault/ - certificate: - role: "front-proxy-client" - CAPath: "clusters/cluster-1/pki/front-proxy" - timeout: 15s - - - name: kubernetes-ca - vault: - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - localPath: /tmp/kubernetes/pki/vault/ - certificate: - role: "" - CAPath: "clusters/cluster-1/pki/kubernetes" - rootCAPath: "clusters/cluster-1/pki/root" - timeout: 15s - - - name: kube-apiserver-server - vault: - role: - name: "kube-apiserver" - path: "clusters/cluster-1/pki/kubernetes" - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - localPath: /tmp/kubernetes/pki/vault/ - certificate: - role: "kube-apiserver" - CAPath: "clusters/cluster-1/pki/kubernetes" - timeout: 15s - - - name: kube-apiserver-kubelet-client - vault: - role: - name: "kube-apiserver" - path: "clusters/cluster-1/pki/kubernetes" - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - localPath: /tmp/kubernetes/pki/vault/ - certificate: - role: "kube-apiserver-kubelet-client" - CAPath: "clusters/cluster-1/pki/kubernetes" - timeout: 15s - - - name: kube-controller-manager-client - vault: - role: - name: "kube-controller-manager-client" - path: "clusters/cluster-1/pki/kubernetes" - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - localPath: /tmp/kubernetes/pki/vault/ - certificate: - role: "kube-controller-manager-client" - CAPath: "clusters/cluster-1/pki/kubernetes" - timeout: 15s - - - name: kube-controller-manager-server - vault: - role: - name: "kube-controller-manager-server" - path: "clusters/cluster-1/pki/kubernetes" - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - localPath: /tmp/kubernetes/pki/vault/ - certificate: - role: "kube-controller-manager-server" - CAPath: "clusters/cluster-1/pki/kubernetes" - timeout: 15s - - - name: kube-scheduler-server - vault: - role: - name: "kube-scheduler-server" - path: "clusters/cluster-1/pki/kubernetes" - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - localPath: /tmp/kubernetes/pki/vault/ - certificate: - role: "kube-scheduler-server" - CAPath: "clusters/cluster-1/pki/kubernetes" - timeout: 15s - - - name: kube-scheduler-client - vault: - role: - name: "kube-scheduler-client" - path: "clusters/cluster-1/pki/kubernetes" - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - localPath: /tmp/kubernetes/pki/vault/ - certificate: - role: "kube-scheduler-client" - CAPath: "clusters/cluster-1/pki/kubernetes" - timeout: 15s - - - name: kubelet-client - vault: - role: - name: "kubelet-client" - path: "clusters/cluster-1/pki/kubernetes" - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - localPath: /tmp/kubernetes/pki/vault/ - certificate: - role: "kubelet-client" - CAPath: "clusters/cluster-1/pki/kubernetes" - timeout: 15s - - - name: kubelet-server - vault: - role: - name: "kubelet-server" - path: "clusters/cluster-1/pki/kubernetes" - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - localPath: /tmp/kubernetes/pki/vault/ - certificate: - role: "kubelet-server" - CAPath: "clusters/cluster-1/pki/kubernetes" - timeout: 15s - - - name: tmpd-ca - vault: - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - localPath: /tmp/kubernetes/pki/vault/ - certificate: - role: "" - CAPath: "clusters/cluster-1/pki/tmpd" - rootCAPath: "clusters/cluster-1/pki/root" - timeout: 15s - - - name: tmpd-peer - vault: - role: - name: "tmpd-peer" - path: "clusters/cluster-1/pki/tmpd" - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - localPath: /tmp/kubernetes/pki/vault/ - certificate: - role: "tmpd-peer" - CAPath: "clusters/cluster-1/pki/tmpd" - timeout: 15s - - - name: tmpd-server - vault: - role: - name: "tmpd-server" - path: "clusters/cluster-1/pki/tmpd" - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - localPath: /tmp/kubernetes/pki/vault/ - certificate: - role: "tmpd-server" - CAPath: "clusters/cluster-1/pki/tmpd" - timeout: 15s - - - name: tmpd-client - vault: - role: - name: "tmpd-client" - path: "clusters/cluster-1/pki/tmpd" - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - localPath: /tmp/kubernetes/pki/vault/ - certificate: - role: "tmpd-client" - CAPath: "clusters/cluster-1/pki/tmpd" - timeout: 15s - - - - name: test-secret - vault: - server: "http://51.250.67.8:9200" - auth: - caBundle: "" - tlsInsecure: true - bootstrap: - token: hvs.RzuJmHubW1V8vj7jFAbZtKLJ - appRole: - name: "test-role" - path: "clusters/cluster-1/approle" - localPath: /tmp/kubernetes/pki/vault/ - kv: - path: clusters/cluster-1/kv - timeout: 15s - -certificates: - - name: front-proxy-ca - issuerRef: - name: front-proxy-ca - isCa: true - ca: - exportedKey: false - generate: false - hostPath: /tmp/kubernetes/pki/ca/ - - - name: front-proxy-client - issuerRef: - name: front-proxy-client - spec: - subject: - commonName: custom:front-proxy-client - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - client auth - ttl: 100h - renewBefore: 50h - hostPath: "/tmp/kubernetes/pki/certs/kube-apiserver/" - - - name: kubernetes-ca - issuerRef: - name: kubernetes-ca - isCa: true - ca: - exportedKey: false - generate: false - hostPath: /tmp/kubernetes/pki/ca/ - - - name: kube-apiserver-server - issuerRef: - name: kube-apiserver-server - spec: - subject: - commonName: custom:kube-apiserver-server - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - server auth - hostnames: - - "localhost" - - "kubernetes" - - "kubernetes.default" - - "kubernetes.default.svc" - - "kubernetes.default.svc.cluster" - - "kubernetes.default.svc.cluster.local" - # - "api.cluster-1.${base_domain}" - ipAddresses: - interfaces: - - eth0 - - lo - # dnsLookup: - # - "api.cluster-1.${base_domain}" - ttl: 100h - hostPath: "/tmp/kubernetes/pki/certs/kube-apiserver/" - - - name: kube-apiserver-kubelet-client - issuerRef: - name: kube-apiserver-kubelet-client - spec: - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - client auth - subject: - commonName: custom:kube-apiserver-kubelet-client - organizationalUnits: - - masters - ttl: 100h - renewBefore: 50h - hostPath: "/tmp/kubernetes/pki/certs/kube-apiserver/" - - - name: kube-controller-manager-client - issuerRef: - name: kube-controller-manager-client - spec: - subject: - commonName: system:kube-controller-manager - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - client auth - ttl: 100h - renewBefore: 50h - hostPath: "/tmp/kubernetes/pki/certs/kube-controller-manager/" - - - name: kube-controller-manager-server - issuerRef: - name: kube-controller-manager-server - spec: - subject: - commonName: custom:kube-controller-manager - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - server auth - hostnames: - - "localhost" - - "kube-controller-manager.default" - - "kube-controller-manager.default.svc" - - "kube-controller-manager.default.svc.cluster" - - "kube-controller-manager.default.svc.cluster.local" - ipAddresses: - interfaces: - - lo - ttl: 100h - renewBefore: 50h - hostPath: "/tmp/kubernetes/pki/certs/kube-controller-manager/" - - - name: kube-scheduler-server - issuerRef: - name: kube-scheduler-server - spec: - subject: - commonName: custom:kube-scheduler - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - server auth - hostnames: - - "localhost" - - "kube-scheduler.default" - - "kube-scheduler.default.svc" - - "kube-scheduler.default.svc.cluster" - - "kube-scheduler.default.svc.cluster.local" - ipAddresses: - interfaces: - - lo - ttl: 100h - renewBefore: 50h - hostPath: "/tmp/kubernetes/pki/certs/kube-scheduler/" - - - name: kube-scheduler-client - issuerRef: - name: kube-scheduler-client - spec: - subject: - commonName: system:kube-scheduler - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - client auth - ttl: 100h - renewBefore: 50h - hostPath: "/tmp/kubernetes/pki/certs/kube-scheduler/" - - # - name: kubelet-client - # issuerRef: - # name: kubelet-client - # vault: - # role: "kubelet-client" - # path: "clusters/cluster-1/pki/kubernetes" - # spec: - # privateKey: - # algorithm: RSA - # encoding: PKCS1 - # size: 4096 - # subject: - # commonName: "system:node:${ instance_name }.${base_domain}" - # organizations: - # - system:nodes - # usages: - # - client auth - # ttl: 100h - # renewBefore: 50h - # hostPath: "/tmp/kubernetes/pki/certs/kubelet/" - - # - name: kubelet-server - # issuerRef: - # name: kubelet-server - # vault: - # role: "kubelet-server" - # path: "clusters/cluster-1/pki/kubernetes" - # spec: - # subject: - # commonName: "system:node:${ instance_name }.${base_domain}" - # organizations: - # - system:nodes - # privateKey: - # algorithm: RSA - # encoding: PKCS1 - # size: 4096 - # usages: - # - server auth - # hostnames: - # - "localhost" - # # - "${ instance_name }.${base_domain}" - # ipAddresses: - # interfaces: - # - lo - # - eth0 - # ttl: 100h - # renewBefore: 50h - # hostPath: "/tmp/kubernetes/pki/certs/kubelet/" - - - name: tmpd-ca - issuerRef: - name: tmpd-ca - isCa: true - ca: - exportedKey: false - generate: false - vault: - role: "" - path: "clusters/cluster-1/pki/tmpd" - rootCAPath: "clusters/cluster-1/pki/root" - hostPath: /tmp/kubernetes/pki/ca/ - - - name: tmpd-peer - issuerRef: - name: tmpd-peer - vault: - role: "tmpd-peer" - path: "clusters/cluster-1/pki/tmpd" - spec: - subject: - commonName: custom:tmpd-peer - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - server auth - - client auth - hostnames: - - "localhost" - # - "${ instance_name }.${base_domain}" - ipAddresses: - interfaces: - - eth0 - - lo - # dnsLookup: - # - "${ instance_name }.${base_domain}" - ttl: 100h - renewBefore: 50h - hostPath: "/tmp/kubernetes/pki/certs/tmpd/" - - - name: tmpd-server - issuerRef: - name: tmpd-server - vault: - role: "tmpd-server" - path: "clusters/cluster-1/pki/tmpd" - spec: - subject: - commonName: custom:tmpd-server - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - server auth - hostnames: - - "localhost" - # - "${ instance_name }.${base_domain}" - ipAddresses: - interfaces: - - eth0 - - lo - # dnsLookup: - # - "${ instance_name }.${base_domain}" - ttl: 100h - renewBefore: 50h - hostPath: "/tmp/kubernetes/pki/certs/tmpd/" - - - name: kube-apiserver-tmpd-client - issuerRef: - name: tmpd-client - vault: - role: "tmpd-client" - path: "clusters/cluster-1/pki/tmpd" - spec: - subject: - commonName: custom:kube-apiserver-tmpd-client - privateKey: - algorithm: RSA - encoding: PKCS1 - size: 4096 - usages: - - client auth - ttl: 100h - renewBefore: 50h - hostPath: "/tmp/kubernetes/pki/certs/kube-apiserver/" - -secrets: - - name: sa-key - issuerRef: - name: test-secret - key: private - hostPath: /tmp/kubernetes/pki/certs/kube-apiserver/ \ No newline at end of file From 340693bbb8b276392666443f6caefcc61ebc9fb8 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 19 Sep 2022 14:55:07 +0300 Subject: [PATCH 149/220] up --- .gitignore | 2 +- internal/issuer/vault/utils.go | 4 ++-- internal/issuer/vault/vault.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 8dd5c0a..fc90926 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ test/ key-keeper -config.yaml role_id secret_id +test.yaml \ No newline at end of file diff --git a/internal/issuer/vault/utils.go b/internal/issuer/vault/utils.go index fac0fe1..e1c2453 100644 --- a/internal/issuer/vault/utils.go +++ b/internal/issuer/vault/utils.go @@ -43,8 +43,8 @@ func readFromFile(path string) ([]byte, error) { func writeToFile(filepath, date string) error { dir := path.Dir(filepath) - if err := os.MkdirAll(dir, 0644); err != nil { - return fmt.Errorf("mkdir all %s : %w", dir, err) + if err := os.MkdirAll(dir, os.ModePerm); err != nil { + return err } return os.WriteFile(filepath, []byte(date), 0644) } diff --git a/internal/issuer/vault/vault.go b/internal/issuer/vault/vault.go index bb32745..d9b79d2 100644 --- a/internal/issuer/vault/vault.go +++ b/internal/issuer/vault/vault.go @@ -108,7 +108,7 @@ func (s *vault) roleID(name string, appRole config.AppRole) (string, error) { } if err = writeToFile(appRole.RoleIDLocalPath, roleID.(string)); err != nil { - return "", fmt.Errorf("save role id path: %s id: %w", appRole.RoleIDLocalPath, err) + return "", fmt.Errorf("save role id path: %s : %w", appRole.RoleIDLocalPath, err) } return roleID.(string), err } @@ -133,7 +133,7 @@ func (s *vault) secretID(name string, appRole config.AppRole) (string, error) { } if err = writeToFile(appRole.RoleIDLocalPath, secretID.(string)); err != nil { - return "", fmt.Errorf("save secret id path: %s id: %w", appRole.RoleIDLocalPath, err) + return "", fmt.Errorf("save secret id path: %s : %w", appRole.RoleIDLocalPath, err) } return secretID.(string), err } From d53ccec2a3e48c7757ebaacad90dabca5be917cb Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 19 Sep 2022 16:21:19 +0300 Subject: [PATCH 150/220] up --- internal/issuer/vault/vault.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/issuer/vault/vault.go b/internal/issuer/vault/vault.go index d9b79d2..79e30ea 100644 --- a/internal/issuer/vault/vault.go +++ b/internal/issuer/vault/vault.go @@ -132,8 +132,8 @@ func (s *vault) secretID(name string, appRole config.AppRole) (string, error) { return "", fmt.Errorf("not found secrete_id") } - if err = writeToFile(appRole.RoleIDLocalPath, secretID.(string)); err != nil { - return "", fmt.Errorf("save secret id path: %s : %w", appRole.RoleIDLocalPath, err) + if err = writeToFile(appRole.SecretIDLocalPath, secretID.(string)); err != nil { + return "", fmt.Errorf("save secret id path: %s : %w", appRole.SecretIDLocalPath, err) } return secretID.(string), err } From 21db18f991e9fdb17b75f0a723c89613c8184d45 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Wed, 21 Sep 2022 14:44:38 +0300 Subject: [PATCH 151/220] up --- internal/issuer/vault/resource.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/issuer/vault/resource.go b/internal/issuer/vault/resource.go index 59b5c06..c84bba5 100644 --- a/internal/issuer/vault/resource.go +++ b/internal/issuer/vault/resource.go @@ -25,7 +25,7 @@ func (s *vault) CheckResource() { zap.L().Debug("checking") wg := &sync.WaitGroup{} - zap.L().Debug("certificate-intermediate-ca") + zap.L().Debug("certificate-ca") for _, cert := range s.certificate { wg.Add(1) go func(c config.Certificate) { From 9a0d89a3d3a8f9a116c19a11f84817df26a4f03b Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 22 Sep 2022 13:42:22 +0300 Subject: [PATCH 152/220] update --- internal/issuer/vault/certificate.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/issuer/vault/certificate.go b/internal/issuer/vault/certificate.go index cef925c..5005baf 100644 --- a/internal/issuer/vault/certificate.go +++ b/internal/issuer/vault/certificate.go @@ -24,6 +24,7 @@ import ( func (s *vault) checkCertificate(certCfg config.Certificate) { cert, err := readCertificate(certCfg.HostPath, certCfg.Name) if cert != nil && time.Until(cert.NotAfter) > certCfg.RenewBefore { + zap.L().Info("read certificate", zap.Float64("remaining time", time.Until(cert.NotAfter).Hours())) return } if err != nil && !os.IsNotExist(err) { From 5c5dde4d32435c626d5e88872e4df2ee85f6b347 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 22 Sep 2022 14:40:12 +0300 Subject: [PATCH 153/220] fix secrete --- config-struct.yaml | 6 --- internal/config/config.go | 1 - internal/config/types.go | 7 ---- internal/controller/controller.go | 6 --- internal/issuer/vault/key.go | 63 ------------------------------- internal/issuer/vault/resource.go | 17 ++------- internal/issuer/vault/secret.go | 10 +---- internal/issuer/vault/utils.go | 4 +- internal/issuer/vault/vault.go | 6 +-- 9 files changed, 9 insertions(+), 111 deletions(-) delete mode 100644 internal/issuer/vault/key.go diff --git a/config-struct.yaml b/config-struct.yaml index dde404a..cc3f1ee 100644 --- a/config-struct.yaml +++ b/config-struct.yaml @@ -54,12 +54,6 @@ certificates: # Описывает список доступных certificates renewBefore: string # за сколько до истечения надо перевыпустить trigger: list of string # список bash команд которые применятся после обновления сертификата -keys: # Описывает список доступных keys - - name: # Имя key - issuerRef: # IssuerRef references a properly configured ACME-type Issuer which should be used to create this Order. If the Issuer does not exist, processing will be retried. If the Issuer is not an 'ACME' Issuer, an error will be returned and the Order will be marked as failed. - name: string # Имя вызываемого ISSUER - hostPath: string # путь, где будет размещен секрет по маске ${hostPathCert}/${keyName} - secrets: # Описывает список доступных secrete - name: # Имя secrete issuerRef: # IssuerRef references a properly configured ACME-type Issuer which should be used to create this Order. If the Issuer does not exist, processing will be retried. If the Issuer is not an 'ACME' Issuer, an error will be returned and the Order will be marked as failed. diff --git a/internal/config/config.go b/internal/config/config.go index 520f5bb..c3ae992 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -51,7 +51,6 @@ func (s *config) GetNewConfig() (newCfg Config, err error) { newCfg.Issuers = append(newCfg.Issuers, cfg.Issuers...) newCfg.Resource.Certificates = append(newCfg.Resource.Certificates, cfg.Resource.Certificates...) - newCfg.Resource.Keys = append(newCfg.Resource.Keys, cfg.Resource.Keys...) newCfg.Resource.Secrets = append(newCfg.Resource.Secrets, cfg.Resource.Secrets...) s.oldConfig[path] = struct{}{} } diff --git a/internal/config/types.go b/internal/config/types.go index a168ece..2176541 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -14,7 +14,6 @@ type Issuer struct { type Resources struct { Certificates []Certificate `yaml:"certificates"` - Keys []Key `yaml:"keys"` Secrets []Secret `yaml:"secrets"` } @@ -29,12 +28,6 @@ type Certificate struct { Trigger []string `yaml:"trigger"` } -type Key struct { - Name string `yaml:"name"` - IssuerRef IssuerRef `yaml:"issuerRef"` - HostPath string `yaml:"hostPath"` -} - type Secret struct { Name string `yaml:"name"` IssuerRef IssuerRef `yaml:"issuerRef"` diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 5164167..95c246c 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -122,12 +122,6 @@ func (s *controller) separateResources(cfg config.Resources) map[string]config.R r[cert.IssuerRef.Name] = resources } - for _, key := range cfg.Keys { - resources := r[key.IssuerRef.Name] - resources.Keys = append(resources.Keys, key) - r[key.IssuerRef.Name] = resources - } - for _, secret := range cfg.Secrets { resources := r[secret.IssuerRef.Name] resources.Secrets = append(resources.Secrets, secret) diff --git a/internal/issuer/vault/key.go b/internal/issuer/vault/key.go deleted file mode 100644 index d4d3db3..0000000 --- a/internal/issuer/vault/key.go +++ /dev/null @@ -1,63 +0,0 @@ -package vault - -import ( - "fmt" - "os" - - "go.uber.org/zap" - - "github.com/fraima/key-keeper/internal/config" -) - -func (s *vault) checkKeyPair(i config.Key) { - private, public, err := s.readKey(i) - if err != nil { - zap.L().Warn( - "read key", - zap.String("name", i.Name), - zap.Error(err), - ) - return - } else { - zap.L().Debug("key is read", zap.String("name", i.Name)) - } - - if err := s.saveKeyOnHost(i.HostPath, private, public); err != nil { - zap.L().Error( - "save key in host", - zap.String("name", i.Name), - zap.String("path", i.HostPath), - zap.Error(err), - ) - return - } - zap.L().Debug("key is save in host", zap.String("name", i.Name)) -} - -func (s *vault) readKey(i config.Key) (private []byte, public []byte, err error) { - storedKye, err := s.Get(s.kvMountPath, i.Name) - if err != nil { - err = fmt.Errorf("get from vault_kv : %w", err) - return - } - - if c, ok := storedKye["private"]; ok { - private = []byte(c.(string)) - } - if k, ok := storedKye["public"]; ok { - public = []byte(k.(string)) - } - - return -} - -func (s *vault) saveKeyOnHost(path string, private, public []byte) error { - if err := os.WriteFile(path+".pem", private, 0600); err != nil { - return fmt.Errorf("failed to save private key with path %s: %w", path, err) - } - - if err := os.WriteFile(path+".pub", public, 0600); err != nil { - return fmt.Errorf("failed to public key file: %w", err) - } - return nil -} diff --git a/internal/issuer/vault/resource.go b/internal/issuer/vault/resource.go index c84bba5..474e9db 100644 --- a/internal/issuer/vault/resource.go +++ b/internal/issuer/vault/resource.go @@ -1,6 +1,7 @@ package vault import ( + "fmt" "sync" "go.uber.org/zap" @@ -12,11 +13,9 @@ func (s *vault) AddResource(r config.Resources) { for _, cert := range r.Certificates { s.certificate[cert.Name] = cert } - for _, key := range r.Keys { - s.key[key.Name] = key - } - for _, secret := range r.Secrets { - s.secret[secret.Name] = secret + for i, secret := range r.Secrets { + name := fmt.Sprintf("%s-%d", secret.Name, i) + s.secret[name] = secret } s.CheckResource() } @@ -39,14 +38,6 @@ func (s *vault) CheckResource() { } wg.Wait() - zap.L().Debug("keys") - for _, key := range s.key { - wg.Add(1) - go func(k config.Key) { - s.checkKeyPair(k) - }(key) - } - zap.L().Debug("secrets") for _, secret := range s.secret { wg.Add(1) diff --git a/internal/issuer/vault/secret.go b/internal/issuer/vault/secret.go index f69faac..12ec105 100644 --- a/internal/issuer/vault/secret.go +++ b/internal/issuer/vault/secret.go @@ -2,7 +2,6 @@ package vault import ( "fmt" - "os" "go.uber.org/zap" @@ -21,7 +20,7 @@ func (s *vault) checkSecret(i config.Secret) { zap.L().Debug("secret is read", zap.String("name", i.Name)) } - if err := s.storeSecret(i.HostPath, secret); err != nil { + if err := writeToFile(i.HostPath, secret); err != nil { zap.L().Error( "store secrete in host", zap.String("name", i.Name), @@ -45,10 +44,3 @@ func (s *vault) readSecret(i config.Secret) (secrete []byte, err error) { } return } - -func (s *vault) storeSecret(path string, secret []byte) error { - if err := os.WriteFile(path, secret, 0600); err != nil { - return fmt.Errorf("failed to save secrete with path %s: %w", path, err) - } - return nil -} diff --git a/internal/issuer/vault/utils.go b/internal/issuer/vault/utils.go index e1c2453..739f45d 100644 --- a/internal/issuer/vault/utils.go +++ b/internal/issuer/vault/utils.go @@ -41,10 +41,10 @@ func readFromFile(path string) ([]byte, error) { return os.ReadFile(path) } -func writeToFile(filepath, date string) error { +func writeToFile(filepath string, date []byte) error { dir := path.Dir(filepath) if err := os.MkdirAll(dir, os.ModePerm); err != nil { return err } - return os.WriteFile(filepath, []byte(date), 0644) + return os.WriteFile(filepath, date, 0644) } diff --git a/internal/issuer/vault/vault.go b/internal/issuer/vault/vault.go index 79e30ea..d83fb8a 100644 --- a/internal/issuer/vault/vault.go +++ b/internal/issuer/vault/vault.go @@ -22,7 +22,6 @@ type vault struct { kvMountPath string certificate map[string]config.Certificate - key map[string]config.Key secret map[string]config.Secret } @@ -54,7 +53,6 @@ func Connect(name string, cfg config.Vault) (controller.Issuer, error) { kvMountPath: cfg.KV.Path, certificate: make(map[string]config.Certificate), - key: make(map[string]config.Key), secret: make(map[string]config.Secret), } @@ -107,7 +105,7 @@ func (s *vault) roleID(name string, appRole config.AppRole) (string, error) { return "", fmt.Errorf("not found role_id") } - if err = writeToFile(appRole.RoleIDLocalPath, roleID.(string)); err != nil { + if err = writeToFile(appRole.RoleIDLocalPath, []byte(roleID.(string))); err != nil { return "", fmt.Errorf("save role id path: %s : %w", appRole.RoleIDLocalPath, err) } return roleID.(string), err @@ -132,7 +130,7 @@ func (s *vault) secretID(name string, appRole config.AppRole) (string, error) { return "", fmt.Errorf("not found secrete_id") } - if err = writeToFile(appRole.SecretIDLocalPath, secretID.(string)); err != nil { + if err = writeToFile(appRole.SecretIDLocalPath, []byte(secretID.(string))); err != nil { return "", fmt.Errorf("save secret id path: %s : %w", appRole.SecretIDLocalPath, err) } return secretID.(string), err From c55edef8d97c198abc20e11ef815eec996d25fcb Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 22 Sep 2022 14:40:56 +0300 Subject: [PATCH 154/220] fix names --- internal/issuer/vault/resource.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/issuer/vault/resource.go b/internal/issuer/vault/resource.go index 474e9db..d361e50 100644 --- a/internal/issuer/vault/resource.go +++ b/internal/issuer/vault/resource.go @@ -10,8 +10,9 @@ import ( ) func (s *vault) AddResource(r config.Resources) { - for _, cert := range r.Certificates { - s.certificate[cert.Name] = cert + for i, cert := range r.Certificates { + name := fmt.Sprintf("%s-%d", cert.Name, i) + s.certificate[name] = cert } for i, secret := range r.Secrets { name := fmt.Sprintf("%s-%d", secret.Name, i) From d93c621a6b5812f0ffccd54bc9b26ed789062b0b Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 22 Sep 2022 15:48:51 +0300 Subject: [PATCH 155/220] change time --- internal/controller/controller.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 95c246c..6656e4d 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -39,7 +39,7 @@ func New( // Start controller of key-keeper. func (s *controller) Start() { - t := time.NewTicker(time.Hour) + t := time.NewTicker(5 * time.Minute) defer t.Stop() for range t.C { s.issuer.Range(func(key, value any) bool { From 3b29aeeb1de2be45b67088010ad9834904176730 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 22 Sep 2022 17:19:58 +0300 Subject: [PATCH 156/220] fix --- internal/issuer/vault/resource.go | 1 + .../kube-apiserver/kube-apiserver-sa.pem | 51 +++++++++++++++++++ .../kube-apiserver/kube-apiserver-sa.pub | 14 +++++ 3 files changed, 66 insertions(+) create mode 100644 kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pem create mode 100644 kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pub diff --git a/internal/issuer/vault/resource.go b/internal/issuer/vault/resource.go index d361e50..a059092 100644 --- a/internal/issuer/vault/resource.go +++ b/internal/issuer/vault/resource.go @@ -43,6 +43,7 @@ func (s *vault) CheckResource() { for _, secret := range s.secret { wg.Add(1) go func(secret config.Secret) { + defer wg.Done() s.checkSecret(secret) }(secret) } diff --git a/kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pem b/kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pem new file mode 100644 index 0000000..e36ed15 --- /dev/null +++ b/kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pem @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIJKgIBAAKCAgEAxOPa8e06ajVnR6fmL1onfgAdKkgt32BZLMD7ko+0xmbTWzWy +MPFwXD0BUfKZYqL30ubuyqXDawQ/+dcwd4NzbDOAkBs45elMoZKUM41L7nyceJqA +Rxn85NX1ZmRK3FSgx+VxIdDdY4xL2g50MfclD4BC9tmYiW1Gq2PhqhOCDiFtzpyx +Lg9gq3CLj0od4krRoGZdwRsm3wyDZndjo4tF3koWIA9Atte9NsVNcK824NB71nR0 +myiWbxITiYf0wMjAPdOFNwbJ1DYDMj2GlYONgiB6WpqNPbwTciMpDI0zO4DCBHK6 +lWDCo/+HkljuBW+7WnJE1NXlbmQKuvCwq5MEbZsIGVxv0y37NfCqZ41I63pJEPPE +OmB8ZlEyKyvGpJJ2oxgaJ0cqXYasZ7w6BFFADHyRatzGY+Ebs6M36Da4kr118XVu +bj10LFcEEVUb+NmIHzu2EKwFY/YUBmaZM1GBlQhktS31A0ri1x4WgUq8rzc09pBO +jruxfMYsvgweSWyuuHu3xkJn0zXFNvcVlCshIu6Td8iGK3NHBVOUvCb53wqt7dh2 +x0gqzmarOwDmZgnbv96biIJm7dzUErWCy6Wxjml8+vHCWkaHkVaiwjEnEKd83nzH +9cLUmTz3c6g8qmsOlqO04Ihih0FZSrM8cJJBKEB8H0dXOnNl7AmibyPAgV0CAwEA +AQKCAgEAnk2pmzym7AA2Ixnu7IGrIRbMXFOedmyMJnyfiQ58Rc0lAL/inpFxSuhN +6GqLQxBO+8ZrlonC3oeTPLj1IhKRuhyKsNMCY3C6CWrGN9DSjVSpphprKz/M4tzY +q1PWEOMGRtLGrG63ojOKRS+74vSYWqdAsCLyDwTKfkEXjtySg/QCys2Xc7YvfohF +3Za1Al4vv6yukvXWwh3YhIlXloYDTh/5PBunZ5t8ac4nXoOyNv3Jo/sMSjhPA8zf +4oNqmZqPXuZzxHNz0WkAFuP7ErmsDEU6uyBqkYlnhSyZ85qP57a1yEfKlxIuTRfG +FDfmYH6ef7FCgHHeP2y2Z+nf0oOpWWGTMlQkafFSP9OIM7P1OmaXXCJIotSL01db +m0ETw7FR8rOVmrKEttQKBPRigvSOCA6dPIizuOgHc64PdpWNvTT5MsoqiL5f7vv3 +7BytX1/E9nBj5WgoWOPuuN4V2m2OA864wdtuBeMQKS3HxVBF27Ka6uUy27pcPOoi +ACIuQswqpF33qoCltD+YznVyLStGdq/wsiKDv3XlZKbuFf/W9ZqKiJxsi1ZzYsJu +H0uevzJ+gZYio8uE8zrToBE4GheOEQ/QqcrRyY32rFAqGfDUilPg09leIG/0E3Pi +GQmCS6Ls6PfkoO4xth0yQWsQXIPMOXDFHacDar+Jh90MUjGkfsECggEBANZBB7D2 +KQtaXqv5C3uoOynu2iw7pZoT7wl+CXMzSEx483x/rcRlmFdBcCK53o33ZxLRU07a +tiY15QN+LwN+b0tXvY2M5Xwnhivhc4iI5uheUwaUs1IURnHSSo6RZNQDY5+PLCic +rUlEA0PlgJlOvuf81DT45vq+TbVa+9Lq7N3Kz7EHx+xqr3tWKphmdUdovVlax+z5 +03FEwer/fPJ3LhD/AOVcOiNgLJlV1dHejtTI58rTd3mTk3RKmW+e4Q1C+pZvKsVD +eT0O4Q/xqTB6bkxugEXYhHp9EmWtf5hssrud/igr/EvSPXswQDuj4x3djd386OLg +BouhL7hKf1q/gVECggEBAOtAtl2WduBV3wwuOjDhtL2eDppO9fcNJPqlWsTgd9bT +C1cZdxX+VH9ZC3pZ/40+oBNUNknZbEUngLzPxbNUegSLzFHOO4SNayogCUbsoNgi +6ZRMbM4wNc/Qvpq1wvCiGqFMvIXr3goGbOeSTg1UK5aq8Z9PBiZm2YI6UEK9j80/ +6e9zRtNVLseNDtYvqgtj7hhcSJfAM6Peo638StxRQ+66I0uMgm5eD9lZSv+h7uZ1 +Ie40wef0k10Xa4oNRhqPwcA0eQrLoQ8RL3QUxohmMUfnYZmS+ZAvNJlvTzh0nthF +fPnEDWMy5R6ftR1ODpVb5YdQxQcMoHDPmM4uqLt13E0CggEBAIZNYz3ZQCc+saOJ +TFpqPRPvBlG93fO0VR2VJOVSmxpcovxCqLE4ogLoIRuTeV9yWukfz+HZFV7kX7cN +zPias7b9u/NUA7IMsH0nKJ3Iez3jipXQdouX7ASDNnshxptjuHoXbC3U8IbBnG5e +GXuAMgkHohnGgDtjOSDadIpk+q+Y5xHod7jJs1BT1gWMDC4ECNVPI413mMQivo/J +MRBoBrdesbgUVNlB+xLvDEYvBUd63Fl2ryjFiiPWc1HVvOrsNlpAOwZGYmQUxJ2S +9WRPCn7csYmWzIxfhD26QQZR9MPIqL2TvOXmVuW2fD0mYUKiU8B4PZ+hoFi8ZEZY +ZHaFHtECggEAREvLJaxS4pnLYSvidOJxqELEloOp4IkOXT239kP8Rn+KYUThT59A +RKBDNsf96rFto27lO9dFGWZ4d1gSWxeBPOSg8nbezIKJw/b8+nwjzduE2Cq/w7Q3 +Sxec3ik6aMWG2aD/chmhomNvJmNRCYmQBfOmpcs5S9i7+JSZTGbf4oRVk9BxlVS7 +ee83iXLY+OmP676OzI9d7orqFc6SpRdqk1myeXJXQ1dHXqAPp9sJEhqbOR5T1NUq +GvJ7o95qpbdqVjRll366STeCAT8uy9ZvJCLGMOF8ViF+MbUg2JDytHKn75K9GDlk +TtmqqNFKZo4BOqF2Ma+2vEloYSMmlRWIWQKCAQEAqDKLWYS+Vf5W9ZzH811d46BA +69dvLzRu0u0odpfxbTP53qZfxSeaTrb99VQqpV3W3/DNwdbkwBweKji0msMGJxNA +DJDjFPCiAe975zN5BOBzz43QuPkwcFHYOJQsebIROHw7lobjhRmTdtfP6gINmU+6 +1CxNGKWV23/wnYKos2o1qJBJCu36j7RA2vrsr3+/Z8hk8EHxGt4DpdMCU9tTgicv +s/TTJd9miqm6T/V2V/Qifpi1C8SkjXlOV9Y/jbElv0vLTTpFlw8vmChMoRVW1Xc4 +rQ9F16PVtnQxqE8pk54hoDmK9/da5FuEVfEDUUggapJuylhjhpp9T/qq21UDtA== +-----END RSA PRIVATE KEY----- diff --git a/kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pub b/kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pub new file mode 100644 index 0000000..a843227 --- /dev/null +++ b/kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pub @@ -0,0 +1,14 @@ +-----BEGIN PUBLIC KEY----- +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxOPa8e06ajVnR6fmL1on +fgAdKkgt32BZLMD7ko+0xmbTWzWyMPFwXD0BUfKZYqL30ubuyqXDawQ/+dcwd4Nz +bDOAkBs45elMoZKUM41L7nyceJqARxn85NX1ZmRK3FSgx+VxIdDdY4xL2g50Mfcl +D4BC9tmYiW1Gq2PhqhOCDiFtzpyxLg9gq3CLj0od4krRoGZdwRsm3wyDZndjo4tF +3koWIA9Atte9NsVNcK824NB71nR0myiWbxITiYf0wMjAPdOFNwbJ1DYDMj2GlYON +giB6WpqNPbwTciMpDI0zO4DCBHK6lWDCo/+HkljuBW+7WnJE1NXlbmQKuvCwq5ME +bZsIGVxv0y37NfCqZ41I63pJEPPEOmB8ZlEyKyvGpJJ2oxgaJ0cqXYasZ7w6BFFA +DHyRatzGY+Ebs6M36Da4kr118XVubj10LFcEEVUb+NmIHzu2EKwFY/YUBmaZM1GB +lQhktS31A0ri1x4WgUq8rzc09pBOjruxfMYsvgweSWyuuHu3xkJn0zXFNvcVlCsh +Iu6Td8iGK3NHBVOUvCb53wqt7dh2x0gqzmarOwDmZgnbv96biIJm7dzUErWCy6Wx +jml8+vHCWkaHkVaiwjEnEKd83nzH9cLUmTz3c6g8qmsOlqO04Ihih0FZSrM8cJJB +KEB8H0dXOnNl7AmibyPAgV0CAwEAAQ== +-----END PUBLIC KEY----- From 109244fd36a924f8efa62f76aff7704731f3e454 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 22 Sep 2022 17:22:51 +0300 Subject: [PATCH 157/220] up --- internal/controller/controller.go | 5 ++ .../kube-apiserver/kube-apiserver-sa.pem | 51 ------------------- .../kube-apiserver/kube-apiserver-sa.pub | 14 ----- 3 files changed, 5 insertions(+), 65 deletions(-) delete mode 100644 kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pem delete mode 100644 kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pub diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 6656e4d..0a487e5 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -90,6 +90,11 @@ func (s *controller) getNewResource() error { ) continue } + zap.L().Info( + "preparing resource", + zap.String("issuer_name", issuer.Name), + zap.String("step", "connect to issuer"), + ) s.issuer.Store(issuer.Name, conn) } diff --git a/kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pem b/kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pem deleted file mode 100644 index e36ed15..0000000 --- a/kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pem +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIJKgIBAAKCAgEAxOPa8e06ajVnR6fmL1onfgAdKkgt32BZLMD7ko+0xmbTWzWy -MPFwXD0BUfKZYqL30ubuyqXDawQ/+dcwd4NzbDOAkBs45elMoZKUM41L7nyceJqA -Rxn85NX1ZmRK3FSgx+VxIdDdY4xL2g50MfclD4BC9tmYiW1Gq2PhqhOCDiFtzpyx -Lg9gq3CLj0od4krRoGZdwRsm3wyDZndjo4tF3koWIA9Atte9NsVNcK824NB71nR0 -myiWbxITiYf0wMjAPdOFNwbJ1DYDMj2GlYONgiB6WpqNPbwTciMpDI0zO4DCBHK6 -lWDCo/+HkljuBW+7WnJE1NXlbmQKuvCwq5MEbZsIGVxv0y37NfCqZ41I63pJEPPE -OmB8ZlEyKyvGpJJ2oxgaJ0cqXYasZ7w6BFFADHyRatzGY+Ebs6M36Da4kr118XVu -bj10LFcEEVUb+NmIHzu2EKwFY/YUBmaZM1GBlQhktS31A0ri1x4WgUq8rzc09pBO -jruxfMYsvgweSWyuuHu3xkJn0zXFNvcVlCshIu6Td8iGK3NHBVOUvCb53wqt7dh2 -x0gqzmarOwDmZgnbv96biIJm7dzUErWCy6Wxjml8+vHCWkaHkVaiwjEnEKd83nzH -9cLUmTz3c6g8qmsOlqO04Ihih0FZSrM8cJJBKEB8H0dXOnNl7AmibyPAgV0CAwEA -AQKCAgEAnk2pmzym7AA2Ixnu7IGrIRbMXFOedmyMJnyfiQ58Rc0lAL/inpFxSuhN -6GqLQxBO+8ZrlonC3oeTPLj1IhKRuhyKsNMCY3C6CWrGN9DSjVSpphprKz/M4tzY -q1PWEOMGRtLGrG63ojOKRS+74vSYWqdAsCLyDwTKfkEXjtySg/QCys2Xc7YvfohF -3Za1Al4vv6yukvXWwh3YhIlXloYDTh/5PBunZ5t8ac4nXoOyNv3Jo/sMSjhPA8zf -4oNqmZqPXuZzxHNz0WkAFuP7ErmsDEU6uyBqkYlnhSyZ85qP57a1yEfKlxIuTRfG -FDfmYH6ef7FCgHHeP2y2Z+nf0oOpWWGTMlQkafFSP9OIM7P1OmaXXCJIotSL01db -m0ETw7FR8rOVmrKEttQKBPRigvSOCA6dPIizuOgHc64PdpWNvTT5MsoqiL5f7vv3 -7BytX1/E9nBj5WgoWOPuuN4V2m2OA864wdtuBeMQKS3HxVBF27Ka6uUy27pcPOoi -ACIuQswqpF33qoCltD+YznVyLStGdq/wsiKDv3XlZKbuFf/W9ZqKiJxsi1ZzYsJu -H0uevzJ+gZYio8uE8zrToBE4GheOEQ/QqcrRyY32rFAqGfDUilPg09leIG/0E3Pi -GQmCS6Ls6PfkoO4xth0yQWsQXIPMOXDFHacDar+Jh90MUjGkfsECggEBANZBB7D2 -KQtaXqv5C3uoOynu2iw7pZoT7wl+CXMzSEx483x/rcRlmFdBcCK53o33ZxLRU07a -tiY15QN+LwN+b0tXvY2M5Xwnhivhc4iI5uheUwaUs1IURnHSSo6RZNQDY5+PLCic -rUlEA0PlgJlOvuf81DT45vq+TbVa+9Lq7N3Kz7EHx+xqr3tWKphmdUdovVlax+z5 -03FEwer/fPJ3LhD/AOVcOiNgLJlV1dHejtTI58rTd3mTk3RKmW+e4Q1C+pZvKsVD -eT0O4Q/xqTB6bkxugEXYhHp9EmWtf5hssrud/igr/EvSPXswQDuj4x3djd386OLg -BouhL7hKf1q/gVECggEBAOtAtl2WduBV3wwuOjDhtL2eDppO9fcNJPqlWsTgd9bT -C1cZdxX+VH9ZC3pZ/40+oBNUNknZbEUngLzPxbNUegSLzFHOO4SNayogCUbsoNgi -6ZRMbM4wNc/Qvpq1wvCiGqFMvIXr3goGbOeSTg1UK5aq8Z9PBiZm2YI6UEK9j80/ -6e9zRtNVLseNDtYvqgtj7hhcSJfAM6Peo638StxRQ+66I0uMgm5eD9lZSv+h7uZ1 -Ie40wef0k10Xa4oNRhqPwcA0eQrLoQ8RL3QUxohmMUfnYZmS+ZAvNJlvTzh0nthF -fPnEDWMy5R6ftR1ODpVb5YdQxQcMoHDPmM4uqLt13E0CggEBAIZNYz3ZQCc+saOJ -TFpqPRPvBlG93fO0VR2VJOVSmxpcovxCqLE4ogLoIRuTeV9yWukfz+HZFV7kX7cN -zPias7b9u/NUA7IMsH0nKJ3Iez3jipXQdouX7ASDNnshxptjuHoXbC3U8IbBnG5e -GXuAMgkHohnGgDtjOSDadIpk+q+Y5xHod7jJs1BT1gWMDC4ECNVPI413mMQivo/J -MRBoBrdesbgUVNlB+xLvDEYvBUd63Fl2ryjFiiPWc1HVvOrsNlpAOwZGYmQUxJ2S -9WRPCn7csYmWzIxfhD26QQZR9MPIqL2TvOXmVuW2fD0mYUKiU8B4PZ+hoFi8ZEZY -ZHaFHtECggEAREvLJaxS4pnLYSvidOJxqELEloOp4IkOXT239kP8Rn+KYUThT59A -RKBDNsf96rFto27lO9dFGWZ4d1gSWxeBPOSg8nbezIKJw/b8+nwjzduE2Cq/w7Q3 -Sxec3ik6aMWG2aD/chmhomNvJmNRCYmQBfOmpcs5S9i7+JSZTGbf4oRVk9BxlVS7 -ee83iXLY+OmP676OzI9d7orqFc6SpRdqk1myeXJXQ1dHXqAPp9sJEhqbOR5T1NUq -GvJ7o95qpbdqVjRll366STeCAT8uy9ZvJCLGMOF8ViF+MbUg2JDytHKn75K9GDlk -TtmqqNFKZo4BOqF2Ma+2vEloYSMmlRWIWQKCAQEAqDKLWYS+Vf5W9ZzH811d46BA -69dvLzRu0u0odpfxbTP53qZfxSeaTrb99VQqpV3W3/DNwdbkwBweKji0msMGJxNA -DJDjFPCiAe975zN5BOBzz43QuPkwcFHYOJQsebIROHw7lobjhRmTdtfP6gINmU+6 -1CxNGKWV23/wnYKos2o1qJBJCu36j7RA2vrsr3+/Z8hk8EHxGt4DpdMCU9tTgicv -s/TTJd9miqm6T/V2V/Qifpi1C8SkjXlOV9Y/jbElv0vLTTpFlw8vmChMoRVW1Xc4 -rQ9F16PVtnQxqE8pk54hoDmK9/da5FuEVfEDUUggapJuylhjhpp9T/qq21UDtA== ------END RSA PRIVATE KEY----- diff --git a/kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pub b/kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pub deleted file mode 100644 index a843227..0000000 --- a/kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pub +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxOPa8e06ajVnR6fmL1on -fgAdKkgt32BZLMD7ko+0xmbTWzWyMPFwXD0BUfKZYqL30ubuyqXDawQ/+dcwd4Nz -bDOAkBs45elMoZKUM41L7nyceJqARxn85NX1ZmRK3FSgx+VxIdDdY4xL2g50Mfcl -D4BC9tmYiW1Gq2PhqhOCDiFtzpyxLg9gq3CLj0od4krRoGZdwRsm3wyDZndjo4tF -3koWIA9Atte9NsVNcK824NB71nR0myiWbxITiYf0wMjAPdOFNwbJ1DYDMj2GlYON -giB6WpqNPbwTciMpDI0zO4DCBHK6lWDCo/+HkljuBW+7WnJE1NXlbmQKuvCwq5ME -bZsIGVxv0y37NfCqZ41I63pJEPPEOmB8ZlEyKyvGpJJ2oxgaJ0cqXYasZ7w6BFFA -DHyRatzGY+Ebs6M36Da4kr118XVubj10LFcEEVUb+NmIHzu2EKwFY/YUBmaZM1GB -lQhktS31A0ri1x4WgUq8rzc09pBOjruxfMYsvgweSWyuuHu3xkJn0zXFNvcVlCsh -Iu6Td8iGK3NHBVOUvCb53wqt7dh2x0gqzmarOwDmZgnbv96biIJm7dzUErWCy6Wx -jml8+vHCWkaHkVaiwjEnEKd83nzH9cLUmTz3c6g8qmsOlqO04Ihih0FZSrM8cJJB -KEB8H0dXOnNl7AmibyPAgV0CAwEAAQ== ------END PUBLIC KEY----- From 6a5b01a8a0a8b5f972dbc9b5af40cf550f9d78ea Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 22 Sep 2022 17:29:13 +0300 Subject: [PATCH 158/220] up --- internal/issuer/vault/resource.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/internal/issuer/vault/resource.go b/internal/issuer/vault/resource.go index a059092..c4b4a7e 100644 --- a/internal/issuer/vault/resource.go +++ b/internal/issuer/vault/resource.go @@ -2,7 +2,6 @@ package vault import ( "fmt" - "sync" "go.uber.org/zap" @@ -23,13 +22,9 @@ func (s *vault) AddResource(r config.Resources) { func (s *vault) CheckResource() { zap.L().Debug("checking") - wg := &sync.WaitGroup{} - zap.L().Debug("certificate-ca") for _, cert := range s.certificate { - wg.Add(1) go func(c config.Certificate) { - defer wg.Done() if c.IsCA { s.checkCA(c) return @@ -37,17 +32,12 @@ func (s *vault) CheckResource() { s.checkCertificate(c) }(cert) } - wg.Wait() - zap.L().Debug("secrets") for _, secret := range s.secret { - wg.Add(1) go func(secret config.Secret) { - defer wg.Done() s.checkSecret(secret) }(secret) } - wg.Wait() zap.L().Debug("done") } From 7d86ff4b0f300eec068370d9e7fa382a7d792841 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Fri, 23 Sep 2022 13:54:11 +0300 Subject: [PATCH 159/220] up --- internal/issuer/vault/certificate.go | 31 ++++++++++++++++++---------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/internal/issuer/vault/certificate.go b/internal/issuer/vault/certificate.go index 5005baf..9705de9 100644 --- a/internal/issuer/vault/certificate.go +++ b/internal/issuer/vault/certificate.go @@ -13,7 +13,6 @@ import ( "os/exec" "path" "regexp" - "strings" "time" "go.uber.org/zap" @@ -49,16 +48,7 @@ func (s *vault) checkCertificate(certCfg config.Certificate) { return } - for _, command := range certCfg.Trigger { - cmd := strings.Split(command, " ") - err := exec.Command(cmd[0], cmd[1:]...).Run() - zap.L().Error( - "certificate trigger", - zap.String("name", certCfg.Name), - zap.String("command", command), - zap.Error(err), - ) - } + trigger(certCfg.Name, certCfg.Trigger) zap.L().Info("certificate generated", zap.String("name", certCfg.Name)) } @@ -202,3 +192,22 @@ func inSlice(str string, sl []string) bool { } return false } + +func trigger(name string, trigger []string) { + for _, command := range trigger { + if err := exec.Command(command).Run(); err != nil { + zap.L().Error( + "certificate trigger", + zap.String("name", name), + zap.String("command", command), + zap.Error(err), + ) + continue + } + zap.L().Info( + "certificate trigger", + zap.String("name", name), + zap.String("command", command), + ) + } +} From 18c5c5f29542f61aff287b54d536fa070760af2e Mon Sep 17 00:00:00 2001 From: irbgeo Date: Fri, 23 Sep 2022 14:07:03 +0300 Subject: [PATCH 160/220] update --- config-struct.yaml | 2 +- internal/config/types.go | 2 +- internal/issuer/vault/certificate.go | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/config-struct.yaml b/config-struct.yaml index cc3f1ee..d9c97e7 100644 --- a/config-struct.yaml +++ b/config-struct.yaml @@ -52,7 +52,7 @@ certificates: # Описывает список доступных certificates ttl: string # на какой промежуток времени заказывается сертификат hostPath: string # путь, где будет размещен секрет по маске ${hostPathCert}/${certName} renewBefore: string # за сколько до истечения надо перевыпустить - trigger: list of string # список bash команд которые применятся после обновления сертификата + trigger: list of list of string # список bash команд которые применятся после обновления сертификата secrets: # Описывает список доступных secrete - name: # Имя secrete diff --git a/internal/config/types.go b/internal/config/types.go index 2176541..1240405 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -25,7 +25,7 @@ type Certificate struct { Spec Spec `yaml:"spec"` HostPath string `yaml:"hostPath"` RenewBefore time.Duration `yaml:"renewBefore"` - Trigger []string `yaml:"trigger"` + Trigger [][]string `yaml:"trigger"` } type Secret struct { diff --git a/internal/issuer/vault/certificate.go b/internal/issuer/vault/certificate.go index 9705de9..36092ad 100644 --- a/internal/issuer/vault/certificate.go +++ b/internal/issuer/vault/certificate.go @@ -193,13 +193,13 @@ func inSlice(str string, sl []string) bool { return false } -func trigger(name string, trigger []string) { +func trigger(name string, trigger [][]string) { for _, command := range trigger { - if err := exec.Command(command).Run(); err != nil { + if err := exec.Command(command[0]).Run(); err != nil { zap.L().Error( "certificate trigger", zap.String("name", name), - zap.String("command", command), + zap.Strings("command", command), zap.Error(err), ) continue @@ -207,7 +207,7 @@ func trigger(name string, trigger []string) { zap.L().Info( "certificate trigger", zap.String("name", name), - zap.String("command", command), + zap.Strings("command", command), ) } } From 0e9167917b9467f93f435f48f449fb2d883a5e67 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Fri, 23 Sep 2022 14:42:28 +0300 Subject: [PATCH 161/220] update --- internal/issuer/vault/vault.go | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/internal/issuer/vault/vault.go b/internal/issuer/vault/vault.go index d83fb8a..b4f262f 100644 --- a/internal/issuer/vault/vault.go +++ b/internal/issuer/vault/vault.go @@ -5,9 +5,11 @@ import ( "fmt" "net/http" "path" + "time" "github.com/hashicorp/vault/api" auth "github.com/hashicorp/vault/api/auth/approle" + "go.uber.org/zap" "github.com/fraima/key-keeper/internal/config" "github.com/fraima/key-keeper/internal/controller" @@ -83,6 +85,8 @@ func Connect(name string, cfg config.Vault) (controller.Issuer, error) { if authInfo == nil { return nil, fmt.Errorf("no auth info was returned after login") } + + go s.authWorker(authInfo) return s, nil } @@ -136,6 +140,34 @@ func (s *vault) secretID(name string, appRole config.AppRole) (string, error) { return secretID.(string), err } +func (s *vault) authWorker(auth *api.Secret) { + token, err := auth.TokenID() + if err != nil { + zap.L().Error("get token from vault", zap.Error(err)) + } + s.cli.SetToken(token) + + ttl, err := auth.TokenTTL() + if err != nil { + zap.L().Error("get token ttl from vault", zap.Error(err)) + } + + t := time.NewTimer(ttl) + for range t.C { + token, err := auth.TokenID() + if err != nil { + zap.L().Error("get token from vault", zap.Error(err)) + } + s.cli.SetToken(token) + + ttl, err := auth.TokenTTL() + if err != nil { + zap.L().Error("get token ttl from vault", zap.Error(err)) + } + t.Reset(ttl) + } +} + // Read secret from vault by path. func (s *vault) Read(path string) (map[string]interface{}, error) { sec, err := s.cli.Logical().Read(path) From 5e197af1725cbdc60f884a62c3da17b879145a30 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Fri, 23 Sep 2022 15:33:38 +0300 Subject: [PATCH 162/220] refactoring --- internal/issuer/vault/vault.go | 114 +-------------------------------- 1 file changed, 1 insertion(+), 113 deletions(-) diff --git a/internal/issuer/vault/vault.go b/internal/issuer/vault/vault.go index b4f262f..b039574 100644 --- a/internal/issuer/vault/vault.go +++ b/internal/issuer/vault/vault.go @@ -4,12 +4,8 @@ import ( "context" "fmt" "net/http" - "path" - "time" "github.com/hashicorp/vault/api" - auth "github.com/hashicorp/vault/api/auth/approle" - "go.uber.org/zap" "github.com/fraima/key-keeper/internal/config" "github.com/fraima/key-keeper/internal/controller" @@ -57,115 +53,7 @@ func Connect(name string, cfg config.Vault) (controller.Issuer, error) { certificate: make(map[string]config.Certificate), secret: make(map[string]config.Secret), } - - roleID, err := s.roleID(name, cfg.Auth.AppRole) - if err != nil { - return nil, fmt.Errorf("get role id: %w", err) - } - secretID, err := s.secretID(name, cfg.Auth.AppRole) - if err != nil { - return nil, fmt.Errorf("get secret id: %w", err) - } - - appRoleAuth, err := auth.NewAppRoleAuth( - roleID, - &auth.SecretID{ - FromString: secretID, - }, - auth.WithMountPath(cfg.Auth.AppRole.Path), - ) - if err != nil { - return nil, err - } - - authInfo, err := client.Auth().Login(context.Background(), appRoleAuth) - if err != nil { - return nil, err - } - if authInfo == nil { - return nil, fmt.Errorf("no auth info was returned after login") - } - - go s.authWorker(authInfo) - return s, nil -} - -func (s *vault) roleID(name string, appRole config.AppRole) (string, error) { - if roleID, rErr := readFromFile(appRole.RoleIDLocalPath); rErr == nil { - return string(roleID), nil - } - - vaultPath := path.Join("auth", appRole.Path, "role", appRole.Name, "role-id") - approle, err := s.Read(vaultPath) - if err != nil { - return "", fmt.Errorf("read role_id for path: %s : %w", vaultPath, err) - } - if approle == nil { - return "", fmt.Errorf("no role_id info was returned") - } - - roleID, ok := approle["role_id"] - if !ok { - return "", fmt.Errorf("not found role_id") - } - - if err = writeToFile(appRole.RoleIDLocalPath, []byte(roleID.(string))); err != nil { - return "", fmt.Errorf("save role id path: %s : %w", appRole.RoleIDLocalPath, err) - } - return roleID.(string), err -} - -func (s *vault) secretID(name string, appRole config.AppRole) (string, error) { - if secretID, rErr := readFromFile(appRole.SecretIDLocalPath); rErr == nil { - return string(secretID), nil - } - - vaultPath := path.Join("auth", appRole.Path, "role", appRole.Name, "secret-id") - approle, err := s.Write(vaultPath, nil) - if err != nil { - return "", fmt.Errorf("read secrete_id for path: %s : %w", vaultPath, err) - } - if approle == nil { - return "", fmt.Errorf("no secrete_id info was returned") - } - - secretID, ok := approle["secret_id"] - if !ok { - return "", fmt.Errorf("not found secrete_id") - } - - if err = writeToFile(appRole.SecretIDLocalPath, []byte(secretID.(string))); err != nil { - return "", fmt.Errorf("save secret id path: %s : %w", appRole.SecretIDLocalPath, err) - } - return secretID.(string), err -} - -func (s *vault) authWorker(auth *api.Secret) { - token, err := auth.TokenID() - if err != nil { - zap.L().Error("get token from vault", zap.Error(err)) - } - s.cli.SetToken(token) - - ttl, err := auth.TokenTTL() - if err != nil { - zap.L().Error("get token ttl from vault", zap.Error(err)) - } - - t := time.NewTimer(ttl) - for range t.C { - token, err := auth.TokenID() - if err != nil { - zap.L().Error("get token from vault", zap.Error(err)) - } - s.cli.SetToken(token) - - ttl, err := auth.TokenTTL() - if err != nil { - zap.L().Error("get token ttl from vault", zap.Error(err)) - } - t.Reset(ttl) - } + return s, s.auth(name, cfg.Auth) } // Read secret from vault by path. From 609eaa556519b7d88893fd14040076c9db3cff9a Mon Sep 17 00:00:00 2001 From: irbgeo Date: Fri, 23 Sep 2022 15:33:45 +0300 Subject: [PATCH 163/220] refactoring --- internal/issuer/vault/vault-auth.go | 123 ++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 internal/issuer/vault/vault-auth.go diff --git a/internal/issuer/vault/vault-auth.go b/internal/issuer/vault/vault-auth.go new file mode 100644 index 0000000..867d088 --- /dev/null +++ b/internal/issuer/vault/vault-auth.go @@ -0,0 +1,123 @@ +package vault + +import ( + "context" + "fmt" + "path" + "time" + + auth "github.com/hashicorp/vault/api/auth/approle" + "go.uber.org/zap" + + "github.com/fraima/key-keeper/internal/config" +) + +func (s *vault) auth(name string, a config.Auth) error { + roleID, err := s.roleID(name, a.AppRole) + if err != nil { + return fmt.Errorf("get role id: %w", err) + } + secretID, err := s.secretID(name, a.AppRole) + if err != nil { + return fmt.Errorf("get secret id: %w", err) + } + + appRoleAuth, err := auth.NewAppRoleAuth( + roleID, + &auth.SecretID{ + FromString: secretID, + }, + ) + if err != nil { + return err + } + + ttl, err := s.updateAuthToken(appRoleAuth) + if err != nil { + return err + } + + go func() { + t := time.NewTimer(ttl) + for range t.C { + ttl, err := s.updateAuthToken(appRoleAuth) + if err != nil { + zap.L().Error("update auth token", zap.Error(err)) + } + t.Reset(ttl) + } + }() + return nil +} + +func (s *vault) roleID(name string, appRole config.AppRole) (string, error) { + if roleID, rErr := readFromFile(appRole.RoleIDLocalPath); rErr == nil { + return string(roleID), nil + } + + vaultPath := path.Join("auth", appRole.Path, "role", appRole.Name, "role-id") + approle, err := s.Read(vaultPath) + if err != nil { + return "", fmt.Errorf("read role_id for path: %s : %w", vaultPath, err) + } + if approle == nil { + return "", fmt.Errorf("no role_id info was returned") + } + + roleID, ok := approle["role_id"] + if !ok { + return "", fmt.Errorf("not found role_id") + } + + if err = writeToFile(appRole.RoleIDLocalPath, []byte(roleID.(string))); err != nil { + return "", fmt.Errorf("save role id path: %s : %w", appRole.RoleIDLocalPath, err) + } + return roleID.(string), err +} + +func (s *vault) secretID(name string, appRole config.AppRole) (string, error) { + if secretID, rErr := readFromFile(appRole.SecretIDLocalPath); rErr == nil { + return string(secretID), nil + } + + vaultPath := path.Join("auth", appRole.Path, "role", appRole.Name, "secret-id") + approle, err := s.Write(vaultPath, nil) + if err != nil { + return "", fmt.Errorf("read secrete_id for path: %s : %w", vaultPath, err) + } + if approle == nil { + return "", fmt.Errorf("no secrete_id info was returned") + } + + secretID, ok := approle["secret_id"] + if !ok { + return "", fmt.Errorf("not found secrete_id") + } + + if err = writeToFile(appRole.SecretIDLocalPath, []byte(secretID.(string))); err != nil { + return "", fmt.Errorf("save secret id path: %s : %w", appRole.SecretIDLocalPath, err) + } + return secretID.(string), err +} + +func (s *vault) updateAuthToken(appRoleAuth *auth.AppRoleAuth) (time.Duration, error) { + authInfo, err := s.cli.Auth().Login(context.Background(), appRoleAuth) + if err != nil { + return 0, err + } + if authInfo == nil { + return 0, fmt.Errorf("no auth info was returned after login") + } + + token, err := authInfo.TokenID() + if err != nil { + return 0, err + } + s.cli.SetToken(token) + + ttl, err := authInfo.TokenTTL() + if err != nil { + return 0, err + } + return ttl, nil +} From 366591270f5390d8b7136587fc60e9cc6bd4043f Mon Sep 17 00:00:00 2001 From: irbgeo Date: Fri, 23 Sep 2022 15:46:33 +0300 Subject: [PATCH 164/220] refactoring --- internal/issuer/vault/vault-auth.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/issuer/vault/vault-auth.go b/internal/issuer/vault/vault-auth.go index 867d088..8cf29b0 100644 --- a/internal/issuer/vault/vault-auth.go +++ b/internal/issuer/vault/vault-auth.go @@ -27,6 +27,7 @@ func (s *vault) auth(name string, a config.Auth) error { &auth.SecretID{ FromString: secretID, }, + auth.WithMountPath(a.AppRole.Path), ) if err != nil { return err From e1cd243a0a5c635149cccd2cc05cf0e17c295ecc Mon Sep 17 00:00:00 2001 From: irbgeo Date: Fri, 23 Sep 2022 16:19:38 +0300 Subject: [PATCH 165/220] frequncy update oken --- internal/issuer/vault/vault-auth.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/issuer/vault/vault-auth.go b/internal/issuer/vault/vault-auth.go index 8cf29b0..05a1e5f 100644 --- a/internal/issuer/vault/vault-auth.go +++ b/internal/issuer/vault/vault-auth.go @@ -39,13 +39,13 @@ func (s *vault) auth(name string, a config.Auth) error { } go func() { - t := time.NewTimer(ttl) + t := time.NewTimer(ttl / 2) for range t.C { ttl, err := s.updateAuthToken(appRoleAuth) if err != nil { zap.L().Error("update auth token", zap.Error(err)) } - t.Reset(ttl) + t.Reset(ttl / 2) } }() return nil @@ -57,15 +57,15 @@ func (s *vault) roleID(name string, appRole config.AppRole) (string, error) { } vaultPath := path.Join("auth", appRole.Path, "role", appRole.Name, "role-id") - approle, err := s.Read(vaultPath) + role, err := s.Read(vaultPath) if err != nil { return "", fmt.Errorf("read role_id for path: %s : %w", vaultPath, err) } - if approle == nil { + if role == nil { return "", fmt.Errorf("no role_id info was returned") } - roleID, ok := approle["role_id"] + roleID, ok := role["role_id"] if !ok { return "", fmt.Errorf("not found role_id") } @@ -82,15 +82,15 @@ func (s *vault) secretID(name string, appRole config.AppRole) (string, error) { } vaultPath := path.Join("auth", appRole.Path, "role", appRole.Name, "secret-id") - approle, err := s.Write(vaultPath, nil) + secret, err := s.Write(vaultPath, nil) if err != nil { return "", fmt.Errorf("read secrete_id for path: %s : %w", vaultPath, err) } - if approle == nil { + if secret == nil { return "", fmt.Errorf("no secrete_id info was returned") } - secretID, ok := approle["secret_id"] + secretID, ok := secret["secret_id"] if !ok { return "", fmt.Errorf("not found secrete_id") } From aacbffd010b1c6d419f10895df4dbf1c3eaf7708 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Fri, 23 Sep 2022 16:46:49 +0300 Subject: [PATCH 166/220] update --- internal/issuer/vault/resource.go | 13 ++++--------- internal/issuer/vault/vault.go | 2 -- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/internal/issuer/vault/resource.go b/internal/issuer/vault/resource.go index c4b4a7e..6dd3b57 100644 --- a/internal/issuer/vault/resource.go +++ b/internal/issuer/vault/resource.go @@ -13,9 +13,10 @@ func (s *vault) AddResource(r config.Resources) { name := fmt.Sprintf("%s-%d", cert.Name, i) s.certificate[name] = cert } - for i, secret := range r.Secrets { - name := fmt.Sprintf("%s-%d", secret.Name, i) - s.secret[name] = secret + for _, secret := range r.Secrets { + go func(secret config.Secret) { + s.checkSecret(secret) + }(secret) } s.CheckResource() } @@ -33,11 +34,5 @@ func (s *vault) CheckResource() { }(cert) } - for _, secret := range s.secret { - go func(secret config.Secret) { - s.checkSecret(secret) - }(secret) - } - zap.L().Debug("done") } diff --git a/internal/issuer/vault/vault.go b/internal/issuer/vault/vault.go index b039574..49d7d18 100644 --- a/internal/issuer/vault/vault.go +++ b/internal/issuer/vault/vault.go @@ -20,7 +20,6 @@ type vault struct { kvMountPath string certificate map[string]config.Certificate - secret map[string]config.Secret } func Connect(name string, cfg config.Vault) (controller.Issuer, error) { @@ -51,7 +50,6 @@ func Connect(name string, cfg config.Vault) (controller.Issuer, error) { kvMountPath: cfg.KV.Path, certificate: make(map[string]config.Certificate), - secret: make(map[string]config.Secret), } return s, s.auth(name, cfg.Auth) } From 1ec1a4cb050a2fb435daa240e42bd146ffeee8da Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Sat, 24 Sep 2022 21:40:26 +0300 Subject: [PATCH 167/220] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D0=B5=D1=82=20=D0=BF=D1=80=D0=B8=D0=BC=D0=B5=D1=80=20?= =?UTF-8?q?=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example.yaml | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 example.yaml diff --git a/example.yaml b/example.yaml new file mode 100644 index 0000000..03d0d99 --- /dev/null +++ b/example.yaml @@ -0,0 +1,100 @@ +--- +issuers: + + - name: kube-apiserver-sa + vault: + server: http://example.com:9200 + auth: + caBundle: + tlsInsecure: true + bootstrap: + token: ${token} + appRole: + name: kube-apiserver-sa + path: "clusters/cluster-1/approle" + secretIDLocalPath: /var/lib/key-keeper/vault/kube-apiserver-sa/secret-id + roleIDLocalPath: /var/lib/key-keeper/vault/kube-apiserver-sa/role-id + kv: + path: clusters/cluster-1/kv + timeout: 15s + + - name: kubernetes-ca + vault: + server: http://example.com:9200 + auth: + caBundle: + tlsInsecure: true + bootstrap: + token: ${token} + appRole: + name: kubernetes-ca + path: "clusters/cluster-1/approle" + secretIDLocalPath: /var/lib/key-keeper/vault/kubernetes-ca/secret-id + roleIDLocalPath: /var/lib/key-keeper/vault/kubernetes-ca/role-id + certificate: + CAPath: "clusters/cluster-1/pki/kubernetes" + rootCAPath: "clusters/cluster-1/pki/root" + timeout: 15s + + - name: kubelet-server + vault: + server: http://example.com:9200 + auth: + caBundle: + tlsInsecure: true + bootstrap: + token: hvs.Ouy9gdxmkEnBmYCVJQsYj1vA + appRole: + name: kubelet-server-ru-central1-a + path: "clusters/cluster-1/approle" + secretIDLocalPath: /var/lib/key-keeper/vault/kubelet-server/secret-id + roleIDLocalPath: /var/lib/key-keeper/vault/kubelet-server/role-id + certificate: + role: kubelet-server + CAPath: "clusters/cluster-1/pki/kubernetes" + timeout: 15s + + +certificates: + + + - name: kubernetes-ca + issuerRef: + name: kubernetes-ca + isCa: true + ca: + exportedKey: false + generate: false + hostPath: "/etc/kubernetes/pki/ca" + + - name: kubelet-server + issuerRef: + name: kubelet-server + spec: + subject: + commonName: "system:node:default.cluster-1.dobry-kot.ru" + usage: + - server auth + privateKey: + algorithm: "RSA" + encoding: "PKCS1" + size: 4096 + ipAddresses: + interfaces: + - lo + - eth* + ttl: 200h + hostnames: + - localhost + - "master-0.cluster-1.dobry-kot.ru" + renewBefore: 100h + hostPath: "/etc/kubernetes/pki/certs/kubelet" + + +secrets: + + - name: kube-apiserver-sa + issuerRef: + name: kube-apiserver-sa + key: public + hostPath: /etc/kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pub From d620e08f377d22e97adb412d8f1e50d1a132d429 Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Sat, 24 Sep 2022 22:48:22 +0300 Subject: [PATCH 168/220] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D0=B5=D1=82=20=D0=B0=D0=BA=D1=82=D1=83=D0=B0=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D1=8B=D0=B9=20=D0=BA=D0=BE=D0=BD=D1=84=D0=B8=D0=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 104 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 62 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 3e5633d..86b0a0b 100644 --- a/README.md +++ b/README.md @@ -29,47 +29,67 @@ Example config.yml ```yaml --- -vault: - address: "http://${VAULT_IP}" # Адрес волта - bootstrap_token: ${VAULT_TOKEN} # Токен для получения secret_id и role_id - # С secret_id и role_id происходит базовая авторизация и получения временного токена. - local_path_to_role_id: "role_id" # Путь где будет сохранен файл с role_id - local_path_to_secret_id: "secret_id" # Путь где будет сохранен файл с secret_id - approle_path: clusters/cluster-1/approle # Путь до аппроли - approle_name: test-role # Название аппроли (для теста выдели аппроль и навесь рут) - request_timeout: "10m" # Таймаут ответа Vault +issuers: + - name: kubernetes-ca + vault: + server: http://example.com:9200 + auth: + caBundle: + tlsInsecure: true + bootstrap: + token: ${token} + appRole: + name: kubernetes-ca + path: "clusters/cluster-1/approle" + secretIDLocalPath: /var/lib/key-keeper/vault/kubernetes-ca/secret-id + roleIDLocalPath: /var/lib/key-keeper/vault/kubernetes-ca/role-id + certificate: + role: kubelet-server + CAPath: "clusters/cluster-1/pki/kubernetes" + rootCAPath: "clusters/cluster-1/pki/root" + kv: + path: clusters/cluster-1/kv + timeout: 15s + certificates: - # Для совместного использования приватного ключа CA,Intermidiat - # - public and private помещается в KV с наименованием ${COMMON_NAME} - vault_kv: "clusters/cluster-1/kv" - reissue_interval: "1d" # интервал перевыпуск - за сутки до истечения перевыпустить. (Хардкод - проверяет раз в час) - # Блок Root_CA отвечает за выпуск корневых сертификатов - на выход не получаем ни сертификат ни ключ от него - # что бы все сертификаты выпускались только с Intermediate. - root_ca: - - common_name: "test" # CN - root_path_ca: "clusters/cluster-1/pki/root" # Путь к сейфу - - # Блок Intermediate_ca отвечает за выпуск промежуточных сертификатов - # Все сертификаты выпускаются в этих сейфах - intermediate_ca: - - common_name: "kubernetes" # CN - root_path_ca: "clusters/cluster-1/pki/root" - cert_path: "clusters/cluster-1/pki/kubernetes" # Путь к сейфу Inermediate CA - host_path: "/etc/kubernetes/pki/ca/root-ca" # Локальный путь, где будет размещен public / private keys - exported_key: false # Этот флаг заказывает Inermediate типа internal/external (в отпут придет private-key или нет) - generate: false # Этот флаг отвечает за сценарий создания нового CA или чтение существующего. - - csr: - - common_name: "system:kube-apiserver-front-proxy-client" # CN - role: "base-role" # system_masters_client # Роль в которой прописаны критерии сертификата (usages,access_ip,access_san,etc) - host_path: "/etc/kubernetes/pki/certs/kube-apiserver/cert" # Локальный путь, где будет размещен public / private keys - cert_path: "clusters/cluster-1/pki/kube-apiserver" # Путь к сейфу Inermediate CA где будет заказан сертификат - trigger: # Триггер выполняемый при обновлении данного csr - - "cmd commands" -keys: - vault_kv: "" - - rsa: - - name: "" - - host_path: "" + - name: kubernetes-ca + issuerRef: + name: kubernetes-ca + isCa: true + ca: + exportedKey: false + generate: false + hostPath: "/etc/kubernetes/pki/ca" + + - name: kubelet-server + issuerRef: + name: kubelet-server + spec: + subject: + commonName: "system:node:master-0.cluster-1.dobry-kot.ru" + usage: + - server auth + privateKey: + algorithm: "RSA" + encoding: "PKCS1" + size: 4096 + ipAddresses: + interfaces: + - lo + - eth* + ttl: 200h + hostnames: + - localhost + - "master-0.cluster-1.dobry-kot.ru" + renewBefore: 100h + hostPath: "/etc/kubernetes/pki/certs/kubelet" + + +secrets: + - name: kube-apiserver-sa + issuerRef: + name: kube-apiserver-sa + key: public + hostPath: /etc/kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pub + ``` From 6c97b01b2169363e00f99ba0ca3be528bf633f9b Mon Sep 17 00:00:00 2001 From: irbgeo Date: Sun, 25 Sep 2022 17:05:50 +0300 Subject: [PATCH 169/220] restore ca cert --- internal/issuer/vault/ca-certificate.go | 29 ++++++++++++++++++++----- internal/issuer/vault/utils.go | 12 +++++----- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/internal/issuer/vault/ca-certificate.go b/internal/issuer/vault/ca-certificate.go index e5a1869..16aafa2 100644 --- a/internal/issuer/vault/ca-certificate.go +++ b/internal/issuer/vault/ca-certificate.go @@ -4,7 +4,9 @@ import ( "crypto/x509" "encoding/pem" "fmt" + "os" "path" + "reflect" "time" "go.uber.org/zap" @@ -19,11 +21,13 @@ func (s *vault) checkCA(cert config.Certificate) { ) defer func() { - if err := storeKeyPair(cert.HostPath, cert.Name, crt, key); err != nil { - zap.L().Error( - "stored intermediate-ca", - zap.Error(err), - ) + if isInfoChanged(cert.HostPath, cert.Name, crt, key) { + if err := storeKeyPair(cert.HostPath, cert.Name, crt, key); err != nil { + zap.L().Error( + "stored intermediate-ca", + zap.Error(err), + ) + } } }() @@ -132,3 +136,18 @@ func (s *vault) readCA(vaultPath string) (crt, key []byte, err error) { } return } + +func isInfoChanged(storePath string, name string, crt, key []byte) bool { + if crt != nil { + if data, err := os.ReadFile(path.Join(storePath, name+".pem")); err != nil || reflect.DeepEqual(crt, data) { + return true + } + } + + if key != nil { + if data, err := os.ReadFile(path.Join(storePath, name+"-key.pem")); err != nil || reflect.DeepEqual(key, data) { + return true + } + } + return false +} diff --git a/internal/issuer/vault/utils.go b/internal/issuer/vault/utils.go index 739f45d..a46fb5f 100644 --- a/internal/issuer/vault/utils.go +++ b/internal/issuer/vault/utils.go @@ -8,19 +8,19 @@ import ( "path" ) -func storeKeyPair(path string, name string, crt, key []byte) error { - if err := os.MkdirAll(path, 0644); err != nil { - return fmt.Errorf("mkdir all %s : %w", path, err) +func storeKeyPair(storePath string, name string, crt, key []byte) error { + if err := os.MkdirAll(storePath, 0644); err != nil { + return fmt.Errorf("mkdir all %s : %w", storePath, err) } if crt != nil { - if err := os.WriteFile(path+"/"+name+".pem", crt, 0644); err != nil { - return fmt.Errorf("failed to save certificate with path %s: %w", path, err) + if err := os.WriteFile(path.Join(storePath, name+".pem"), crt, 0644); err != nil { + return fmt.Errorf("failed to save certificate with path %s: %w", storePath, err) } } if key != nil { - if err := os.WriteFile(path+"/"+name+"-key.pem", key, 0600); err != nil { + if err := os.WriteFile(path.Join(storePath, name+"-key.pem"), key, 0600); err != nil { return fmt.Errorf("failed to save key file: %w", err) } } From 55b25a59ae376f8022c433cab026e2711a1c7f9e Mon Sep 17 00:00:00 2001 From: irbgeo Date: Sun, 25 Sep 2022 18:54:18 +0300 Subject: [PATCH 170/220] trigger --- internal/issuer/vault/certificate.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/internal/issuer/vault/certificate.go b/internal/issuer/vault/certificate.go index 36092ad..c5fcf9a 100644 --- a/internal/issuer/vault/certificate.go +++ b/internal/issuer/vault/certificate.go @@ -195,7 +195,14 @@ func inSlice(str string, sl []string) bool { func trigger(name string, trigger [][]string) { for _, command := range trigger { - if err := exec.Command(command[0]).Run(); err != nil { + var err error + if len(command) == 1 { + err = exec.Command(command[0]).Run() + } else { + err = exec.Command(command[0], command[1:]...).Run() + } + + if err != nil { zap.L().Error( "certificate trigger", zap.String("name", name), From b73ac902d5174c6115019705515d6e4d4dd37576 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 26 Sep 2022 12:31:36 +0300 Subject: [PATCH 171/220] with update --- config-struct.yaml | 3 +- internal/config/types.go | 17 ++++---- internal/issuer/vault/ca-certificate.go | 2 +- internal/issuer/vault/certificate.go | 55 +++++++++++++------------ internal/issuer/vault/secret.go | 12 +++--- 5 files changed, 46 insertions(+), 43 deletions(-) diff --git a/config-struct.yaml b/config-struct.yaml index d9c97e7..e6b41e2 100644 --- a/config-struct.yaml +++ b/config-struct.yaml @@ -51,7 +51,8 @@ certificates: # Описывает список доступных certificates dnsLookup: list of string ttl: string # на какой промежуток времени заказывается сертификат hostPath: string # путь, где будет размещен секрет по маске ${hostPathCert}/${certName} - renewBefore: string # за сколько до истечения надо перевыпустить + withUpdate: bool + updateBefore: string # за сколько до истечения надо перевыпустить trigger: list of list of string # список bash команд которые применятся после обновления сертификата secrets: # Описывает список доступных secrete diff --git a/internal/config/types.go b/internal/config/types.go index 1240405..c565893 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -18,14 +18,15 @@ type Resources struct { } type Certificate struct { - Name string `yaml:"name"` - IssuerRef IssuerRef `yaml:"issuerRef"` - IsCA bool `yaml:"isCa"` - CA CA `yaml:"ca"` - Spec Spec `yaml:"spec"` - HostPath string `yaml:"hostPath"` - RenewBefore time.Duration `yaml:"renewBefore"` - Trigger [][]string `yaml:"trigger"` + Name string `yaml:"name"` + IssuerRef IssuerRef `yaml:"issuerRef"` + IsCA bool `yaml:"isCa"` + CA CA `yaml:"ca"` + Spec Spec `yaml:"spec"` + HostPath string `yaml:"hostPath"` + WithUpdate bool `yaml:"withUpdate"` + UpdateBefore time.Duration `yaml:"updateBefore"` + Trigger [][]string `yaml:"trigger"` } type Secret struct { diff --git a/internal/issuer/vault/ca-certificate.go b/internal/issuer/vault/ca-certificate.go index 16aafa2..1cfdf50 100644 --- a/internal/issuer/vault/ca-certificate.go +++ b/internal/issuer/vault/ca-certificate.go @@ -39,7 +39,7 @@ func (s *vault) checkCA(cert config.Certificate) { if err != nil { err = fmt.Errorf("parse : %w", err) } - if ca != nil && time.Until(ca.NotAfter) < cert.RenewBefore { + if ca != nil && time.Until(ca.NotAfter) < cert.UpdateBefore { err = fmt.Errorf("expired until(h) %f", time.Until(ca.NotAfter).Hours()) } } diff --git a/internal/issuer/vault/certificate.go b/internal/issuer/vault/certificate.go index c5fcf9a..97bd13f 100644 --- a/internal/issuer/vault/certificate.go +++ b/internal/issuer/vault/certificate.go @@ -22,34 +22,37 @@ import ( func (s *vault) checkCertificate(certCfg config.Certificate) { cert, err := readCertificate(certCfg.HostPath, certCfg.Name) - if cert != nil && time.Until(cert.NotAfter) > certCfg.RenewBefore { - zap.L().Info("read certificate", zap.Float64("remaining time", time.Until(cert.NotAfter).Hours())) + if cert != nil && time.Until(cert.NotAfter) > certCfg.UpdateBefore { + zap.L().Info("read", zap.Float64("remaining time", time.Until(cert.NotAfter).Hours())) return } if err != nil && !os.IsNotExist(err) { - zap.L().Error("read certificate", zap.String("path", certCfg.HostPath), zap.Error(err)) + zap.L().Error("read", zap.String("path", certCfg.HostPath), zap.Error(err)) } - crt, key, err := s.generateCertificate(certCfg.Spec) - if err != nil { - zap.L().Error( - "generate certificate", - zap.String("name", certCfg.Name), - zap.Error(err), - ) - } + if os.IsNotExist(err) && certCfg.WithUpdate { + crt, key, err := s.generateCertificate(certCfg.Spec) + if err != nil { + zap.L().Error( + "generate", + zap.String("certificate_name", certCfg.Name), + zap.Error(err), + ) + } - if err = storeKeyPair(certCfg.HostPath, certCfg.Name, crt, key); err != nil { - zap.L().Error( - "store certificate", - zap.String("name", certCfg.Name), - zap.Error(err), - ) - return - } + err = storeKeyPair(certCfg.HostPath, certCfg.Name, crt, key) + if err != nil { + zap.L().Error( + "store", + zap.String("certificate_name", certCfg.Name), + zap.Error(err), + ) + return + } - trigger(certCfg.Name, certCfg.Trigger) - zap.L().Info("certificate generated", zap.String("name", certCfg.Name)) + trigger(certCfg.Name, certCfg.Trigger) + zap.L().Info("generated", zap.String("certificate_name", certCfg.Name)) + } } func (s *vault) generateCertificate(certSpec config.Spec) ([]byte, []byte, error) { @@ -108,7 +111,7 @@ func createCSR(spec config.Spec) (crt, key []byte, err error) { csr, err := x509.CreateCertificateRequest(rand.Reader, &template, pk) if err != nil { - err = fmt.Errorf("create certificate request: %w", err) + err = fmt.Errorf("create request: %w", err) return } @@ -204,16 +207,16 @@ func trigger(name string, trigger [][]string) { if err != nil { zap.L().Error( - "certificate trigger", - zap.String("name", name), + "trigger", + zap.String("certificate_name", name), zap.Strings("command", command), zap.Error(err), ) continue } zap.L().Info( - "certificate trigger", - zap.String("name", name), + "trigger", + zap.String("certificate_name", name), zap.Strings("command", command), ) } diff --git a/internal/issuer/vault/secret.go b/internal/issuer/vault/secret.go index 12ec105..ae5dc74 100644 --- a/internal/issuer/vault/secret.go +++ b/internal/issuer/vault/secret.go @@ -12,24 +12,22 @@ func (s *vault) checkSecret(i config.Secret) { secret, err := s.readSecret(i) if err != nil { zap.L().Warn( - "read secret", - zap.String("name", i.Name), + "read", + zap.String("secret_name", i.Name), zap.Error(err), ) - } else { - zap.L().Debug("secret is read", zap.String("name", i.Name)) } if err := writeToFile(i.HostPath, secret); err != nil { zap.L().Error( - "store secrete in host", - zap.String("name", i.Name), + "store in host", + zap.String("secret_name", i.Name), zap.String("path", i.HostPath), zap.Error(err), ) return } - zap.L().Debug("secret is stored", zap.String("name", i.Name)) + zap.L().Debug("secret is stored", zap.String("secret_name", i.Name)) } func (s *vault) readSecret(i config.Secret) (secrete []byte, err error) { From 30c4b73ac807e58896f2b3889473b0fabc135b6e Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 26 Sep 2022 13:29:21 +0300 Subject: [PATCH 172/220] fix --- internal/issuer/vault/certificate.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/issuer/vault/certificate.go b/internal/issuer/vault/certificate.go index 97bd13f..da1df19 100644 --- a/internal/issuer/vault/certificate.go +++ b/internal/issuer/vault/certificate.go @@ -30,7 +30,7 @@ func (s *vault) checkCertificate(certCfg config.Certificate) { zap.L().Error("read", zap.String("path", certCfg.HostPath), zap.Error(err)) } - if os.IsNotExist(err) && certCfg.WithUpdate { + if os.IsNotExist(err) || certCfg.WithUpdate { crt, key, err := s.generateCertificate(certCfg.Spec) if err != nil { zap.L().Error( From b08bc56368d7b062ea9599c699e4ba069f3eb57b Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 27 Sep 2022 16:12:26 +0300 Subject: [PATCH 173/220] refactoring | improving logging --- cmd/key-keeper/main.go | 10 ++- internal/config/config.go | 13 +-- internal/controller/controller.go | 101 ++++++++++++------------ internal/controller/error.go | 8 ++ internal/issuer/vault/ca-certificate.go | 73 +++++------------ internal/issuer/vault/certificate.go | 57 ++++++------- internal/issuer/vault/resource.go | 7 +- internal/issuer/vault/secret.go | 29 +++---- internal/issuer/vault/utils.go | 24 ++++-- internal/issuer/vault/vault-auth.go | 7 +- internal/issuer/vault/vault.go | 8 +- 11 files changed, 152 insertions(+), 185 deletions(-) create mode 100644 internal/controller/error.go diff --git a/cmd/key-keeper/main.go b/cmd/key-keeper/main.go index 84ddcb6..7f7831b 100644 --- a/cmd/key-keeper/main.go +++ b/cmd/key-keeper/main.go @@ -47,15 +47,19 @@ func main() { zap.L().Debug("configuration", zap.Any("config", cfg), zap.String("version", Version)) cntl := controller.New( - cfg, + cfg.GetNewConfig, vault.Connect, ) - go cntl.RefreshResource() - go cntl.Start() + + if err := cntl.Start(); err != nil { + zap.L().Fatal("start controller", zap.Error(err)) + } zap.L().Info("started") ch := make(chan os.Signal, 1) signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM) <-ch + + zap.L().Info("goodbye") } diff --git a/internal/config/config.go b/internal/config/config.go index c3ae992..5e5d628 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -31,7 +31,7 @@ func New(configDir, configNameLayout string) (*config, error) { } // GetNewConfig return new config from config dir. -func (s *config) GetNewConfig() (newCfg Config, err error) { +func (s *config) GetNewConfig() (cfg Config, err error) { list, err := s.getNewConfigFiles() if err != nil { return @@ -43,15 +43,16 @@ func (s *config) GetNewConfig() (newCfg Config, err error) { zap.L().Error("read config file", zap.String("path", path), zap.Error(err)) continue } - var cfg Config - if err = yaml.Unmarshal(data, &cfg); err != nil { + + var tmpCfg Config + if err = yaml.Unmarshal(data, &tmpCfg); err != nil { zap.L().Error("unmarshal config file", zap.String("path", path), zap.Error(err)) continue } - newCfg.Issuers = append(newCfg.Issuers, cfg.Issuers...) - newCfg.Resource.Certificates = append(newCfg.Resource.Certificates, cfg.Resource.Certificates...) - newCfg.Resource.Secrets = append(newCfg.Resource.Secrets, cfg.Resource.Secrets...) + cfg.Issuers = append(cfg.Issuers, tmpCfg.Issuers...) + cfg.Resource.Certificates = append(cfg.Resource.Certificates, tmpCfg.Resource.Certificates...) + cfg.Resource.Secrets = append(cfg.Resource.Secrets, tmpCfg.Resource.Secrets...) s.oldConfig[path] = struct{}{} } diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 0a487e5..4a14319 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -1,7 +1,6 @@ package controller import ( - "errors" "fmt" "sync" "time" @@ -11,114 +10,116 @@ import ( "github.com/fraima/key-keeper/internal/config" ) -type Config interface { - GetNewConfig() (config.Config, error) -} - type Issuer interface { AddResource(config.Resources) CheckResource() } type controller struct { - config Config + getConfig func() (config.Config, error) issuerConnector func(name string, cfg config.Vault) (Issuer, error) issuer sync.Map } func New( - config Config, + config func() (config.Config, error), vaultConnector func(name string, cfg config.Vault) (Issuer, error), ) *controller { return &controller{ - config: config, + getConfig: config, issuerConnector: vaultConnector, } } // Start controller of key-keeper. -func (s *controller) Start() { - t := time.NewTicker(5 * time.Minute) - defer t.Stop() - for range t.C { - s.issuer.Range(func(key, value any) bool { - value.(Issuer).CheckResource() - return true - }) - } -} - -func (s *controller) RefreshResource() { +func (s *controller) Start() error { if err := s.getNewResource(); err != nil { - zap.L().Error("refresh resources", zap.Error(err)) + return err } - t := time.NewTicker(30 * time.Second) - defer t.Stop() - for range t.C { - if err := s.getNewResource(); err != nil { - zap.L().Error("refresh resources", zap.Error(err)) + + go func() { + for range time.NewTicker(30 * time.Second).C { + if err := s.getNewResource(); err != nil { + zap.L().Error("refresh_resources", zap.Error(err)) + } } - } + }() + + go func() { + for range time.NewTicker(time.Hour).C { + s.issuer.Range(func(key, value any) bool { + value.(Issuer).CheckResource() + return true + }) + } + }() + + return nil } func (s *controller) getNewResource() error { - cfg, err := s.config.GetNewConfig() + cfg, err := s.getConfig() if err != nil { return fmt.Errorf("get new configs: %w", err) } for _, issuer := range cfg.Issuers { - // TODO: что делать если приходит несколько issuer с одинаковыми именами _, isExist := s.issuer.Load(issuer.Name) if isExist { - zap.L().Warn( - "preparing resource", + zap.L().Error( + "issuer_connect", zap.String("issuer_name", issuer.Name), - zap.String("step", "connect to issuer"), - zap.Error(errors.New("issuer is exist")), + zap.String("status", "failed"), + zap.Error(errIssuerIsExist), ) continue } + conn, err := s.issuerConnector(issuer.Name, issuer.Vault) if err != nil { zap.L().Error( - "preparing resource", + "issuer_connect", zap.String("issuer_name", issuer.Name), - zap.String("step", "connect to issuer"), + zap.String("status", "failed"), zap.Error(err), ) continue } - zap.L().Info( - "preparing resource", - zap.String("issuer_name", issuer.Name), - zap.String("step", "connect to issuer"), - ) s.issuer.Store(issuer.Name, conn) + + zap.L().Debug( + "issuer_connect", + zap.String("issuer_name", issuer.Name), + zap.String("status", "success"), + ) } - resources := s.separateResources(cfg.Resource) + resources := s.separateResourcesByIssuers(cfg.Resource) for issuerName, rCfg := range resources { - r, isExist := s.issuer.Load(issuerName) + issuer, isExist := s.issuer.Load(issuerName) if !isExist { - zap.L().Warn( - "preparing resource", + zap.L().Error( + "add_resource", zap.String("issuer_name", issuerName), - zap.String("step", "add recource"), - zap.Error(errors.New("issuer is not exist")), + zap.String("status", "failed"), + zap.Error(errIssuerIsNotExist), ) continue } - r.(Issuer).AddResource(rCfg) - } + issuer.(Issuer).AddResource(rCfg) + zap.L().Debug( + "add_resource", + zap.String("issuer_name", issuerName), + zap.String("status", "success"), + ) + } return nil } -func (s *controller) separateResources(cfg config.Resources) map[string]config.Resources { - // TODO: что делать если приходит несколько ресурсов с одинаковыми именами для одного issuer +func (s *controller) separateResourcesByIssuers(cfg config.Resources) map[string]config.Resources { r := make(map[string]config.Resources) for _, cert := range cfg.Certificates { diff --git a/internal/controller/error.go b/internal/controller/error.go new file mode 100644 index 0000000..3caa61f --- /dev/null +++ b/internal/controller/error.go @@ -0,0 +1,8 @@ +package controller + +import "errors" + +var ( + errIssuerIsExist = errors.New("issuer is exist") + errIssuerIsNotExist = errors.New("issuer is notexist") +) diff --git a/internal/issuer/vault/ca-certificate.go b/internal/issuer/vault/ca-certificate.go index 1cfdf50..b1473fd 100644 --- a/internal/issuer/vault/ca-certificate.go +++ b/internal/issuer/vault/ca-certificate.go @@ -2,11 +2,8 @@ package vault import ( "crypto/x509" - "encoding/pem" "fmt" - "os" "path" - "reflect" "time" "go.uber.org/zap" @@ -15,60 +12,44 @@ import ( ) func (s *vault) checkCA(cert config.Certificate) { + logger := zap.L().With(zap.String("resource_type", "intermediate_ca"), zap.String("name", cert.Name)) + var ( crt, key []byte err error ) defer func() { - if isInfoChanged(cert.HostPath, cert.Name, crt, key) { - if err := storeKeyPair(cert.HostPath, cert.Name, crt, key); err != nil { - zap.L().Error( - "stored intermediate-ca", - zap.Error(err), - ) - } + if err := storeKeyPair(cert.HostPath, cert.Name, crt, key); err != nil { + logger.Error("store", zap.Error(err)) } + logger.Debug("store") }() crt, key, err = s.readCA(s.caPath) if err == nil { var ca *x509.Certificate - pBlock, _ := pem.Decode(crt) - ca, err = x509.ParseCertificate(pBlock.Bytes) - if err != nil { - err = fmt.Errorf("parse : %w", err) - } - if ca != nil && time.Until(ca.NotAfter) < cert.UpdateBefore { - err = fmt.Errorf("expired until(h) %f", time.Until(ca.NotAfter).Hours()) + ca, err = parseCertificate(crt) + if err == nil { + logger.Debug("ttl", zap.Float64("remaining time(h)", time.Until(ca.NotAfter).Hours())) + if time.Until(ca.NotAfter) < cert.UpdateBefore { + err = fmt.Errorf("expired until(h) %f", time.Until(ca.NotAfter).Hours()) + } } } - if err != nil { - zap.L().Warn( - "intermediate ca", - zap.String("name", cert.Name), - zap.Error(err), - ) - } else { + if err == nil { return } + logger.Warn("check", zap.Error(err)) if cert.CA.Generate { crt, key, err = s.generateCA(cert) if err != nil { - zap.L().Error( - "generate intermediate-ca", - zap.String("name", cert.Name), - zap.Error(err), - ) + logger.Error("generate", zap.Error(err)) return - } else { - zap.L().Info( - "intermediate-ca generated", - zap.String("name", cert.Name), - ) } + zap.L().Info("generated") } } @@ -90,7 +71,6 @@ func (s *vault) generateCA(cert config.Certificate) (crt, key []byte, err error) return } - // send the intermediate ca 's CSR to the root CA for signing icaData := map[string]interface{}{ "csr": csr["csr"], "format": "pem_bundle", @@ -114,11 +94,11 @@ func (s *vault) generateCA(cert config.Certificate) (crt, key []byte, err error) return } - if c, ok := ica["certificate"]; ok { - crt = []byte(c.(string)) + if data, ok := ica["certificate"]; ok { + crt = []byte(data.(string)) } - if k, ok := csr["private_key"]; ok { - key = []byte(k.(string)) + if data, ok := csr["private_key"]; ok { + key = []byte(data.(string)) } return } @@ -136,18 +116,3 @@ func (s *vault) readCA(vaultPath string) (crt, key []byte, err error) { } return } - -func isInfoChanged(storePath string, name string, crt, key []byte) bool { - if crt != nil { - if data, err := os.ReadFile(path.Join(storePath, name+".pem")); err != nil || reflect.DeepEqual(crt, data) { - return true - } - } - - if key != nil { - if data, err := os.ReadFile(path.Join(storePath, name+"-key.pem")); err != nil || reflect.DeepEqual(key, data) { - return true - } - } - return false -} diff --git a/internal/issuer/vault/certificate.go b/internal/issuer/vault/certificate.go index da1df19..1875b99 100644 --- a/internal/issuer/vault/certificate.go +++ b/internal/issuer/vault/certificate.go @@ -20,38 +20,36 @@ import ( "github.com/fraima/key-keeper/internal/config" ) -func (s *vault) checkCertificate(certCfg config.Certificate) { - cert, err := readCertificate(certCfg.HostPath, certCfg.Name) - if cert != nil && time.Until(cert.NotAfter) > certCfg.UpdateBefore { - zap.L().Info("read", zap.Float64("remaining time", time.Until(cert.NotAfter).Hours())) - return +func (s *vault) checkCertificate(cert config.Certificate) { + logger := zap.L().With(zap.String("resource_type", "certificate"), zap.String("name", cert.Name)) + + crt, err := readCertificate(cert.HostPath, cert.Name) + if crt != nil { + logger.Debug("ttl", zap.Float64("remaining time(h)", time.Until(crt.NotAfter).Hours())) + if time.Until(crt.NotAfter) < cert.UpdateBefore { + err = fmt.Errorf("expired until(h) %f", time.Until(crt.NotAfter).Hours()) + } } - if err != nil && !os.IsNotExist(err) { - zap.L().Error("read", zap.String("path", certCfg.HostPath), zap.Error(err)) + + if err == nil { + return } + zap.L().Warn("check", zap.Error(err)) - if os.IsNotExist(err) || certCfg.WithUpdate { - crt, key, err := s.generateCertificate(certCfg.Spec) + if os.IsNotExist(err) || cert.WithUpdate { + crt, key, err := s.generateCertificate(cert.Spec) if err != nil { - zap.L().Error( - "generate", - zap.String("certificate_name", certCfg.Name), - zap.Error(err), - ) + zap.L().Error("generate", zap.Error(err)) } - err = storeKeyPair(certCfg.HostPath, certCfg.Name, crt, key) + err = storeKeyPair(cert.HostPath, cert.Name, crt, key) if err != nil { - zap.L().Error( - "store", - zap.String("certificate_name", certCfg.Name), - zap.Error(err), - ) + zap.L().Error("store", zap.Error(err)) return } - trigger(certCfg.Name, certCfg.Trigger) - zap.L().Info("generated", zap.String("certificate_name", certCfg.Name)) + trigger(cert.Trigger, logger) + zap.L().Debug("generated") } } @@ -196,7 +194,7 @@ func inSlice(str string, sl []string) bool { return false } -func trigger(name string, trigger [][]string) { +func trigger(trigger [][]string, logger *zap.Logger) { for _, command := range trigger { var err error if len(command) == 1 { @@ -206,18 +204,9 @@ func trigger(name string, trigger [][]string) { } if err != nil { - zap.L().Error( - "trigger", - zap.String("certificate_name", name), - zap.Strings("command", command), - zap.Error(err), - ) + logger.Error("trigger", zap.Strings("command", command), zap.Error(err)) continue } - zap.L().Info( - "trigger", - zap.String("certificate_name", name), - zap.Strings("command", command), - ) + logger.Debug("trigger", zap.Strings("command", command)) } } diff --git a/internal/issuer/vault/resource.go b/internal/issuer/vault/resource.go index 6dd3b57..5b27793 100644 --- a/internal/issuer/vault/resource.go +++ b/internal/issuer/vault/resource.go @@ -1,17 +1,14 @@ package vault import ( - "fmt" - "go.uber.org/zap" "github.com/fraima/key-keeper/internal/config" ) func (s *vault) AddResource(r config.Resources) { - for i, cert := range r.Certificates { - name := fmt.Sprintf("%s-%d", cert.Name, i) - s.certificate[name] = cert + for _, cert := range r.Certificates { + s.certificate[cert.Name] = cert } for _, secret := range r.Secrets { go func(secret config.Secret) { diff --git a/internal/issuer/vault/secret.go b/internal/issuer/vault/secret.go index ae5dc74..4dcc9e9 100644 --- a/internal/issuer/vault/secret.go +++ b/internal/issuer/vault/secret.go @@ -9,36 +9,27 @@ import ( ) func (s *vault) checkSecret(i config.Secret) { + logger := zap.L().With(zap.String("resource_type", "secret"), zap.String("name", i.Name)) + secret, err := s.readSecret(i) if err != nil { - zap.L().Warn( - "read", - zap.String("secret_name", i.Name), - zap.Error(err), - ) + logger.Warn("read", zap.Error(err)) } - if err := writeToFile(i.HostPath, secret); err != nil { - zap.L().Error( - "store in host", - zap.String("secret_name", i.Name), - zap.String("path", i.HostPath), - zap.Error(err), - ) - return + err = writeToFile(i.HostPath, secret) + if err != nil { + zap.L().Error("store", zap.String("path", i.HostPath), zap.Error(err)) } - zap.L().Debug("secret is stored", zap.String("secret_name", i.Name)) } -func (s *vault) readSecret(i config.Secret) (secrete []byte, err error) { +func (s *vault) readSecret(i config.Secret) ([]byte, error) { storedSecrete, err := s.Get(s.kvMountPath, i.Name) if err != nil { - err = fmt.Errorf("get from vault_kv : %w", err) - return + return nil, fmt.Errorf("get from vault_kv : %w", err) } if data, ok := storedSecrete[i.Key]; ok { - secrete = []byte(data.(string)) + return []byte(data.(string)), nil } - return + return nil, fmt.Errorf("secrete not found : %w", err) } diff --git a/internal/issuer/vault/utils.go b/internal/issuer/vault/utils.go index a46fb5f..53ba07c 100644 --- a/internal/issuer/vault/utils.go +++ b/internal/issuer/vault/utils.go @@ -6,6 +6,7 @@ import ( "fmt" "os" "path" + "reflect" ) func storeKeyPair(storePath string, name string, crt, key []byte) error { @@ -14,14 +15,22 @@ func storeKeyPair(storePath string, name string, crt, key []byte) error { } if crt != nil { - if err := os.WriteFile(path.Join(storePath, name+".pem"), crt, 0644); err != nil { - return fmt.Errorf("failed to save certificate with path %s: %w", storePath, err) + crtPath := path.Join(storePath, name+".pem") + data, err := os.ReadFile(crtPath) + if err != nil || !reflect.DeepEqual(crt, data) { + if err := os.WriteFile(path.Join(crtPath, name+".pem"), crt, 0644); err != nil { + return fmt.Errorf("failed to save certificate with path %s: %w", storePath, err) + } } } if key != nil { - if err := os.WriteFile(path.Join(storePath, name+"-key.pem"), key, 0600); err != nil { - return fmt.Errorf("failed to save key file: %w", err) + keyPath := path.Join(storePath, name+"-key.pem") + data, err := os.ReadFile(keyPath) + if err != nil || !reflect.DeepEqual(key, data) { + if err := os.WriteFile(path.Join(storePath, name+"-key.pem"), key, 0600); err != nil { + return fmt.Errorf("failed to save key file: %w", err) + } } } return nil @@ -32,15 +41,14 @@ func readCertificate(path string, name string) (*x509.Certificate, error) { if err != nil { return nil, err } + return parseCertificate(crt) +} +func parseCertificate(crt []byte) (*x509.Certificate, error) { pBlock, _ := pem.Decode(crt) return x509.ParseCertificate(pBlock.Bytes) } -func readFromFile(path string) ([]byte, error) { - return os.ReadFile(path) -} - func writeToFile(filepath string, date []byte) error { dir := path.Dir(filepath) if err := os.MkdirAll(dir, os.ModePerm); err != nil { diff --git a/internal/issuer/vault/vault-auth.go b/internal/issuer/vault/vault-auth.go index 05a1e5f..ab2f6fb 100644 --- a/internal/issuer/vault/vault-auth.go +++ b/internal/issuer/vault/vault-auth.go @@ -3,6 +3,7 @@ package vault import ( "context" "fmt" + "os" "path" "time" @@ -43,7 +44,7 @@ func (s *vault) auth(name string, a config.Auth) error { for range t.C { ttl, err := s.updateAuthToken(appRoleAuth) if err != nil { - zap.L().Error("update auth token", zap.Error(err)) + zap.L().Error("update auth token", zap.String("issuer_name", name), zap.Error(err)) } t.Reset(ttl / 2) } @@ -52,7 +53,7 @@ func (s *vault) auth(name string, a config.Auth) error { } func (s *vault) roleID(name string, appRole config.AppRole) (string, error) { - if roleID, rErr := readFromFile(appRole.RoleIDLocalPath); rErr == nil { + if roleID, rErr := os.ReadFile(appRole.RoleIDLocalPath); rErr == nil { return string(roleID), nil } @@ -77,7 +78,7 @@ func (s *vault) roleID(name string, appRole config.AppRole) (string, error) { } func (s *vault) secretID(name string, appRole config.AppRole) (string, error) { - if secretID, rErr := readFromFile(appRole.SecretIDLocalPath); rErr == nil { + if secretID, rErr := os.ReadFile(appRole.SecretIDLocalPath); rErr == nil { return string(secretID), nil } diff --git a/internal/issuer/vault/vault.go b/internal/issuer/vault/vault.go index 49d7d18..5a66a0d 100644 --- a/internal/issuer/vault/vault.go +++ b/internal/issuer/vault/vault.go @@ -34,9 +34,11 @@ func Connect(name string, cfg config.Vault) (controller.Issuer, error) { if err != nil { return nil, fmt.Errorf("new vault client: %w", err) } + client.SetToken(cfg.Auth.Bootstrap.Token) if !cfg.Auth.TLSInsecure { - if err = client.CloneConfig().ConfigureTLS(&api.TLSConfig{CACert: cfg.Auth.CABundle}); err != nil { + err = client.CloneConfig().ConfigureTLS(&api.TLSConfig{CACert: cfg.Auth.CABundle}) + if err != nil { return nil, fmt.Errorf("configuring tls: %w", err) } } @@ -72,13 +74,13 @@ func (s *vault) Write(path string, data map[string]interface{}) (map[string]inte return nil, err } -// Put in KV. +// Put in Vault KV. func (s *vault) Put(kvMountPath, secretePath string, data map[string]interface{}) error { _, err := s.cli.KVv2(kvMountPath).Put(context.Background(), secretePath, data) return err } -// Get from KV. +// Get from Vault KV. func (s *vault) Get(kvMountPath, secretePath string) (map[string]interface{}, error) { sec, err := s.cli.KVv2(kvMountPath).Get(context.Background(), secretePath) if sec != nil { From 89b98efea3ef17472ba95fe6590b36c7c7635e91 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 27 Sep 2022 16:31:48 +0300 Subject: [PATCH 174/220] up --- internal/config/config.go | 1 + internal/controller/controller.go | 31 ++++++++----------------------- internal/issuer/vault/vault.go | 1 + 3 files changed, 10 insertions(+), 23 deletions(-) diff --git a/internal/config/config.go b/internal/config/config.go index 5e5d628..1e071f9 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -16,6 +16,7 @@ type config struct { oldConfig map[string]struct{} } +// New return interface for work with config. func New(configDir, configNameLayout string) (*config, error) { reg, err := regexp.Compile(configNameLayout) if err != nil { diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 4a14319..e80c339 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -22,6 +22,7 @@ type controller struct { issuer sync.Map } +// New returns controller. func New( config func() (config.Config, error), vaultConnector func(name string, cfg config.Vault) (Issuer, error), @@ -32,12 +33,13 @@ func New( } } -// Start controller of key-keeper. +// Start controller. func (s *controller) Start() error { if err := s.getNewResource(); err != nil { return err } + // start getting new resources and issuers go func() { for range time.NewTicker(30 * time.Second).C { if err := s.getNewResource(); err != nil { @@ -46,6 +48,7 @@ func (s *controller) Start() error { } }() + // start resource checking go func() { for range time.NewTicker(time.Hour).C { s.issuer.Range(func(key, value any) bool { @@ -78,43 +81,25 @@ func (s *controller) getNewResource() error { conn, err := s.issuerConnector(issuer.Name, issuer.Vault) if err != nil { - zap.L().Error( - "issuer_connect", - zap.String("issuer_name", issuer.Name), - zap.String("status", "failed"), - zap.Error(err), - ) + zap.L().Error("issuer_connect", zap.String("issuer_name", issuer.Name), zap.Error(err)) continue } s.issuer.Store(issuer.Name, conn) - zap.L().Debug( - "issuer_connect", - zap.String("issuer_name", issuer.Name), - zap.String("status", "success"), - ) + zap.L().Debug("issuer_connect", zap.String("issuer_name", issuer.Name)) } resources := s.separateResourcesByIssuers(cfg.Resource) for issuerName, rCfg := range resources { issuer, isExist := s.issuer.Load(issuerName) if !isExist { - zap.L().Error( - "add_resource", - zap.String("issuer_name", issuerName), - zap.String("status", "failed"), - zap.Error(errIssuerIsNotExist), - ) + zap.L().Error("add_resource", zap.String("issuer_name", issuerName), zap.Error(errIssuerIsNotExist)) continue } issuer.(Issuer).AddResource(rCfg) - zap.L().Debug( - "add_resource", - zap.String("issuer_name", issuerName), - zap.String("status", "success"), - ) + zap.L().Debug("add_resource", zap.String("issuer_name", issuerName)) } return nil } diff --git a/internal/issuer/vault/vault.go b/internal/issuer/vault/vault.go index 5a66a0d..c0a38b3 100644 --- a/internal/issuer/vault/vault.go +++ b/internal/issuer/vault/vault.go @@ -22,6 +22,7 @@ type vault struct { certificate map[string]config.Certificate } +// Connect to vault issuer. func Connect(name string, cfg config.Vault) (controller.Issuer, error) { client, err := api.NewClient( &api.Config{ From 7eb9c60577547263f6b4ddb982edcc7cc4b717f9 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Wed, 28 Sep 2022 16:39:21 +0300 Subject: [PATCH 175/220] up --- config-struct.yaml | 1 + internal/config/types.go | 1 + internal/issuer/vault/vault.go | 17 ++++++++++++++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/config-struct.yaml b/config-struct.yaml index e6b41e2..f249a0d 100644 --- a/config-struct.yaml +++ b/config-struct.yaml @@ -8,6 +8,7 @@ issuers: # Описывает список доступных issuers tlsInsecure: bool # new при указании тру скипать ssl верификацию bootstrap: # блок авторизации в Vault по бутстрап токену tokenPath: string # rename $bootstrap_token + file: string appRole: # блок авторизации в Vault по аппроли name: string # rename $approle_name path: string # rename $approle_path diff --git a/internal/config/types.go b/internal/config/types.go index c565893..2f0c2df 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -59,6 +59,7 @@ type CertVault struct { type Bootstrap struct { Token string `yaml:"token"` + File string `yaml:"file"` } type AppRole struct { diff --git a/internal/issuer/vault/vault.go b/internal/issuer/vault/vault.go index c0a38b3..693fd39 100644 --- a/internal/issuer/vault/vault.go +++ b/internal/issuer/vault/vault.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/http" + "os" "github.com/hashicorp/vault/api" @@ -36,7 +37,12 @@ func Connect(name string, cfg config.Vault) (controller.Issuer, error) { return nil, fmt.Errorf("new vault client: %w", err) } - client.SetToken(cfg.Auth.Bootstrap.Token) + token, err := getToken(cfg.Auth.Bootstrap) + if err != nil { + return nil, fmt.Errorf("get vault token: %w", err) + } + + client.SetToken(token) if !cfg.Auth.TLSInsecure { err = client.CloneConfig().ConfigureTLS(&api.TLSConfig{CACert: cfg.Auth.CABundle}) if err != nil { @@ -89,3 +95,12 @@ func (s *vault) Get(kvMountPath, secretePath string) (map[string]interface{}, er } return nil, err } + +func getToken(b config.Bootstrap) (string, error) { + if b.Token != "" { + return b.Token, nil + } + + data, err := os.ReadFile(b.File) + return string(data), err +} From 07d778a3daf2bbf25819022b8393b41a514ae917 Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Wed, 28 Sep 2022 23:01:09 +0300 Subject: [PATCH 176/220] =?UTF-8?q?=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D0=B5=D1=82=20=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=82=D1=83?= =?UTF-8?q?=D1=80=D1=83=20=D0=BA=D0=BE=D0=BD=D1=84=D0=B8=D0=B3=D0=BE=D0=B2?= =?UTF-8?q?=20=D0=B2=20=D1=80=D0=B8=D0=B4=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/README.md b/README.md index 86b0a0b..41c564a 100644 --- a/README.md +++ b/README.md @@ -93,3 +93,76 @@ secrets: hostPath: /etc/kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pub ``` +## Описание структуры конфигов: + +#### ISSUERS: + +ключ | тип | описание +--- | --- | --- +**`issuers `**| list | список инструкций подключений +`.name` | string | имя инструкции +`.vault.server` | string | адрес Vault server +`.vault.auth.caBundle` | object | ca bundle для tls +`.vault.auth.tlsInsecure` | bool | отключение проверки tls +`.vault.auth.bootstrap` | object | описание метода авторизации для получения secret_id_role_id +`.vault.auth.bootstrap.tokenPath` | string | временный токен Vault +`.vault.auth.bootstrap.file` | string | путь к временномсу токену Vault +`.vault.auth.appRole` | object | описание авторизации по approle +`.vault.auth.appRole.name` | string | имя approle +`.vault.auth.appRole.path` | string | базовый путь approle в Vault +`.vault.auth.appRole.roleIDLocalPath` | string | локальный путь, где будет искать role_id для авторизации +`.vault.auth.appRole.secretIDLocalPath` | string | локальный путь, где будет искать secret_id для авторизации +`.vault.kv` | object | описание доступа в Vault к Key Value стореджу +`.vault.kv.path` | string | путь в Vault до Key Value стореджа +`.vault.certificate`| object | инструция доступа к vault роли для выпуска сертификата +`.vault.certificate.role` | string | имя роли через которую будет выпускаться сертификат +`.vault.certificate.CAPath `| string | базовый путь PKI хранилища, где прописана роль +`.vault.certificate.rootCAPath` | string | базовый путь PKI root хранилища от кого будет выписываться intermediate +`.vault.timeout ` | string | максимальное время ответа сервера Vault + +#### CERTIFICATES: +ключ | тип | описание +--- | --- | --- +**`certificates `**| list | список инструкций заказа сертификатов из Vault +`.name` | string | имя инструкции +`.issuerRef` | object | ссылка на инструкцию issuer через которую произведется авторизация +`.issuerRef.name` | string | имя инструкции issuer +`.isCa` | bool | указатель, что заказывается сертификат типа CA +`.ca` | object | описание расширения для заказа CA +`.ca.exportedKey` | bool | инструкция - запрашивать приватный ключ или нет (требуется pki типа external) +`.ca.generate` | bool | создаст intermediate или запросит существующий (требуются права на создание intermediate) +`.spec` | object | поля для генерации сертификата +`.spec.subject` | object | Описывает принадлежность сертификата к... +`.spec.subject.commonName` | string | * +`.spec.subject.country` | list | * +`.spec.subject.localite` | list | * +`.spec.subject.organization` | list | * +`.spec.subject.organizationalUnit` | list | * +`.spec.subject.province` | list | * +`.spec.subject.postalCode` | list | * +`.spec.subject.streetAddress` | list | * +`.spec.subject.serialNumber` | string | * +`.spec.privateKey` | object | Описание алгоритма для приватного ключа +`.spec.privateKey.algorithm` | string | Алгоритм +`.spec.privateKey.encoding` | string | Метод формирования +`.spec.privateKey.size` | integer | 2048 / 4096 +`.spec.hostnames` | list | список имен для блока alternative names +`.spec.ipAddresses` | object | описывает какие ip адреса попадут в ipSans +`.spec.ipAddresses.static` | list | список статичных ip адресов который попадет в ipSans +`.spec.ipAddresses.interfaces` | list | список ip адресов, взятый с интерфейсов хоста, попадет в ipSans +`.spec.ipAddresses.dnsLookup` | list | список ip адресов, взятый из функции dnslookup статичной A записи, попадет в ipSans +`.spec.ttl` | string | срок на который заказывается сертификат +`.hostPath` | string | путь в локальной файловой системе, где будет сохранен сертификат +`.withUpdate` | bool | данный параметр создаст сертификат без последующего перевыпуска +`.updateBefore` | string | время до истечения сертификата - при достижении сертификат перевыпустится +`.trigger` | list | список баш команд, которые выполнятся после обновления сертификата + +#### SECRETS: +ключ | тип | описание +--- | --- | --- +**`secrets `**| list | список инструкций заказа секрета из Vault +`.name` | string | имя инструкции и одновременно имя секрета в Vault +`.issuerRef` | object | ссылка на инструкцию issuer через которую произведется авторизация +`.issuerRef.name` | string | имя инструкции issuer +`.key` | string | ключ в объекта секрета +`.hostPath` | string | путь в локальной файловой системе, где будет сохранен секрет From dded5969cefb3e272145e7b82139e85e081f9694 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 29 Sep 2022 14:48:17 +0300 Subject: [PATCH 177/220] update --- Dockerfile | 2 +- Makefile | 6 +- README.md | 144 ++++++++++++++++++++++----------------------- config-struct.yaml | 64 -------------------- example.yaml | 100 ------------------------------- 5 files changed, 78 insertions(+), 238 deletions(-) delete mode 100644 config-struct.yaml delete mode 100644 example.yaml diff --git a/Dockerfile b/Dockerfile index a798fd1..d2c218a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.18.3-alpine3.16 as builder +FROM golang:1.19.1-alpine3.16 as builder WORKDIR /app diff --git a/Makefile b/Makefile index e27e0d0..25febd2 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ release = $(shell cat .release) tag = $(DOCKER_USER)/key-keeper:$(release) +pwd = $(shell pwd) build-and-push: docker build -t $(tag) --build-arg VERSION=$(release) -f Dockerfile . @@ -7,4 +8,7 @@ build-and-push: formatting: go install github.com/daixiang0/gci@latest - gci write --skip-generated -s standard -s default -s "prefix(github.com/fraima/key-keeper)" . \ No newline at end of file + gci write --skip-generated -s standard -s default -s "prefix(github.com/fraima/key-keeper)" . + +linter: + docker run --rm -v $(pwd):/app -w /app golangci/golangci-lint:v1.49.0 golangci-lint run -v \ No newline at end of file diff --git a/README.md b/README.md index 41c564a..7016394 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ make build-and-push DOCKER_USER=geoirb go build -o key-keeper cmd/key-keeper/main.go ``` -# Run bim +## Run bin ```bash key-keeper -config-dir /path/to/config-dir -config-regexp .*.conf @@ -24,8 +24,7 @@ key-keeper -config-dir /path/to/config-dir -config-regexp .*.conf > > config-regexp - регуляроное выражения для имени файлов которые содержат конфиги для key-keeper - -Example config.yml +## Пример конфига ```yaml --- @@ -34,7 +33,7 @@ issuers: vault: server: http://example.com:9200 auth: - caBundle: + caBundle: tlsInsecure: true bootstrap: token: ${token} @@ -84,85 +83,86 @@ certificates: renewBefore: 100h hostPath: "/etc/kubernetes/pki/certs/kubelet" - secrets: - name: kube-apiserver-sa issuerRef: name: kube-apiserver-sa - key: public + key: public hostPath: /etc/kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pub - ``` + ## Описание структуры конфигов: #### ISSUERS: -ключ | тип | описание ---- | --- | --- -**`issuers `**| list | список инструкций подключений -`.name` | string | имя инструкции -`.vault.server` | string | адрес Vault server -`.vault.auth.caBundle` | object | ca bundle для tls -`.vault.auth.tlsInsecure` | bool | отключение проверки tls -`.vault.auth.bootstrap` | object | описание метода авторизации для получения secret_id_role_id -`.vault.auth.bootstrap.tokenPath` | string | временный токен Vault -`.vault.auth.bootstrap.file` | string | путь к временномсу токену Vault -`.vault.auth.appRole` | object | описание авторизации по approle -`.vault.auth.appRole.name` | string | имя approle -`.vault.auth.appRole.path` | string | базовый путь approle в Vault -`.vault.auth.appRole.roleIDLocalPath` | string | локальный путь, где будет искать role_id для авторизации -`.vault.auth.appRole.secretIDLocalPath` | string | локальный путь, где будет искать secret_id для авторизации -`.vault.kv` | object | описание доступа в Vault к Key Value стореджу -`.vault.kv.path` | string | путь в Vault до Key Value стореджа -`.vault.certificate`| object | инструция доступа к vault роли для выпуска сертификата -`.vault.certificate.role` | string | имя роли через которую будет выпускаться сертификат -`.vault.certificate.CAPath `| string | базовый путь PKI хранилища, где прописана роль -`.vault.certificate.rootCAPath` | string | базовый путь PKI root хранилища от кого будет выписываться intermediate -`.vault.timeout ` | string | максимальное время ответа сервера Vault +| ключ | тип | описание | +| --------------------------------------- | ------ | ----------------------------------------------------------------------- | +| **`issuers `** | list | список инструкций подключений | +| `.name` | string | имя инструкции | +| `.vault.server` | string | адрес Vault server | +| `.vault.auth.caBundle` | object | ca bundle для tls | +| `.vault.auth.tlsInsecure` | bool | отключение проверки tls | +| `.vault.auth.bootstrap` | object | описание метода авторизации для получения secret_id_role_id | +| `.vault.auth.bootstrap.tokenPath` | string | временный токен Vault | +| `.vault.auth.bootstrap.file` | string | путь к временномсу токену Vault | +| `.vault.auth.appRole` | object | описание авторизации по approle | +| `.vault.auth.appRole.name` | string | имя approle | +| `.vault.auth.appRole.path` | string | базовый путь approle в Vault | +| `.vault.auth.appRole.roleIDLocalPath` | string | локальный путь, где будет искать role_id для авторизации | +| `.vault.auth.appRole.secretIDLocalPath` | string | локальный путь, где будет искать secret_id для авторизации | +| `.vault.kv` | object | описание доступа в Vault к Key Value стореджу | +| `.vault.kv.path` | string | путь в Vault до Key Value стореджа | +| `.vault.certificate` | object | инструция доступа к vault роли для выпуска сертификата | +| `.vault.certificate.role` | string | имя роли через которую будет выпускаться сертификат | +| `.vault.certificate.CAPath ` | string | базовый путь PKI хранилища, где прописана роль | +| `.vault.certificate.rootCAPath` | string | базовый путь PKI root хранилища от кого будет выписываться intermediate | +| `.vault.timeout ` | string | максимальное время ответа сервера Vault | #### CERTIFICATES: -ключ | тип | описание ---- | --- | --- -**`certificates `**| list | список инструкций заказа сертификатов из Vault -`.name` | string | имя инструкции -`.issuerRef` | object | ссылка на инструкцию issuer через которую произведется авторизация -`.issuerRef.name` | string | имя инструкции issuer -`.isCa` | bool | указатель, что заказывается сертификат типа CA -`.ca` | object | описание расширения для заказа CA -`.ca.exportedKey` | bool | инструкция - запрашивать приватный ключ или нет (требуется pki типа external) -`.ca.generate` | bool | создаст intermediate или запросит существующий (требуются права на создание intermediate) -`.spec` | object | поля для генерации сертификата -`.spec.subject` | object | Описывает принадлежность сертификата к... -`.spec.subject.commonName` | string | * -`.spec.subject.country` | list | * -`.spec.subject.localite` | list | * -`.spec.subject.organization` | list | * -`.spec.subject.organizationalUnit` | list | * -`.spec.subject.province` | list | * -`.spec.subject.postalCode` | list | * -`.spec.subject.streetAddress` | list | * -`.spec.subject.serialNumber` | string | * -`.spec.privateKey` | object | Описание алгоритма для приватного ключа -`.spec.privateKey.algorithm` | string | Алгоритм -`.spec.privateKey.encoding` | string | Метод формирования -`.spec.privateKey.size` | integer | 2048 / 4096 -`.spec.hostnames` | list | список имен для блока alternative names -`.spec.ipAddresses` | object | описывает какие ip адреса попадут в ipSans -`.spec.ipAddresses.static` | list | список статичных ip адресов который попадет в ipSans -`.spec.ipAddresses.interfaces` | list | список ip адресов, взятый с интерфейсов хоста, попадет в ipSans -`.spec.ipAddresses.dnsLookup` | list | список ip адресов, взятый из функции dnslookup статичной A записи, попадет в ipSans -`.spec.ttl` | string | срок на который заказывается сертификат -`.hostPath` | string | путь в локальной файловой системе, где будет сохранен сертификат -`.withUpdate` | bool | данный параметр создаст сертификат без последующего перевыпуска -`.updateBefore` | string | время до истечения сертификата - при достижении сертификат перевыпустится -`.trigger` | list | список баш команд, которые выполнятся после обновления сертификата + +| ключ | тип | описание | +| ---------------------------------- | ------- | ----------------------------------------------------------------------------------------- | +| **`certificates `** | list | список инструкций заказа сертификатов из Vault | +| `.name` | string | имя инструкции | +| `.issuerRef` | object | ссылка на инструкцию issuer через которую произведется авторизация | +| `.issuerRef.name` | string | имя инструкции issuer | +| `.isCa` | bool | указатель, что заказывается сертификат типа CA | +| `.ca` | object | описание расширения для заказа CA | +| `.ca.exportedKey` | bool | инструкция - запрашивать приватный ключ или нет (требуется pki типа external) | +| `.ca.generate` | bool | создаст intermediate или запросит существующий (требуются права на создание intermediate) | +| `.spec` | object | поля для генерации сертификата | +| `.spec.subject` | object | Описывает принадлежность сертификата к... | +| `.spec.subject.commonName` | string | \* | +| `.spec.subject.country` | list | \* | +| `.spec.subject.localite` | list | \* | +| `.spec.subject.organization` | list | \* | +| `.spec.subject.organizationalUnit` | list | \* | +| `.spec.subject.province` | list | \* | +| `.spec.subject.postalCode` | list | \* | +| `.spec.subject.streetAddress` | list | \* | +| `.spec.subject.serialNumber` | string | \* | +| `.spec.privateKey` | object | Описание алгоритма для приватного ключа | +| `.spec.privateKey.algorithm` | string | Алгоритм | +| `.spec.privateKey.encoding` | string | Метод формирования | +| `.spec.privateKey.size` | integer | 2048 / 4096 | +| `.spec.hostnames` | list | список имен для блока alternative names | +| `.spec.ipAddresses` | object | описывает какие ip адреса попадут в ipSans | +| `.spec.ipAddresses.static` | list | список статичных ip адресов который попадет в ipSans | +| `.spec.ipAddresses.interfaces` | list | список ip адресов, взятый с интерфейсов хоста, попадет в ipSans | +| `.spec.ipAddresses.dnsLookup` | list | список ip адресов, взятый из функции dnslookup статичной A записи, попадет в ipSans | +| `.spec.ttl` | string | срок на который заказывается сертификат | +| `.hostPath` | string | путь в локальной файловой системе, где будет сохранен сертификат | +| `.withUpdate` | bool | данный параметр создаст сертификат без последующего перевыпуска | +| `.updateBefore` | string | время до истечения сертификата - при достижении сертификат перевыпустится | +| `.trigger` | list | список баш команд, которые выполнятся после обновления сертификата | #### SECRETS: -ключ | тип | описание ---- | --- | --- -**`secrets `**| list | список инструкций заказа секрета из Vault -`.name` | string | имя инструкции и одновременно имя секрета в Vault -`.issuerRef` | object | ссылка на инструкцию issuer через которую произведется авторизация -`.issuerRef.name` | string | имя инструкции issuer -`.key` | string | ключ в объекта секрета -`.hostPath` | string | путь в локальной файловой системе, где будет сохранен секрет + +| ключ | тип | описание | +| ----------------- | ------ | ------------------------------------------------------------------ | +| **`secrets `** | list | список инструкций заказа секрета из Vault | +| `.name` | string | имя инструкции и одновременно имя секрета в Vault | +| `.issuerRef` | object | ссылка на инструкцию issuer через которую произведется авторизация | +| `.issuerRef.name` | string | имя инструкции issuer | +| `.key` | string | ключ в объекта секрета | +| `.hostPath` | string | путь в локальной файловой системе, где будет сохранен секрет | diff --git a/config-struct.yaml b/config-struct.yaml deleted file mode 100644 index f249a0d..0000000 --- a/config-struct.yaml +++ /dev/null @@ -1,64 +0,0 @@ ---- -issuers: # Описывает список доступных issuers - - name: string # Имя issuer - vault: # Все переменные global.Vault.* могут быть переопределены тут в блоке vault - server: string # rename $address (адрес волта) - auth: # блок авторизации в Vault - caBundle: string # new (сертификат для подключения к волту - при http не должен фигурировать) - tlsInsecure: bool # new при указании тру скипать ssl верификацию - bootstrap: # блок авторизации в Vault по бутстрап токену - tokenPath: string # rename $bootstrap_token - file: string - appRole: # блок авторизации в Vault по аппроли - name: string # rename $approle_name - path: string # rename $approle_path - roleIDLocalPath: string # rename $local_path_to_role_id - secretIDLocalPath: string - kv: - path: string - certificate: - role: string # альтернатива блоку csr[*].role - CAPath: string # Путь к сейфу Inermediate CA где будет заказан сертификат - rootCAPath: string # Путь к root CA - timeout: string # строка формата "1s", таймаут для любого обращения к issuer - -certificates: # Описывает список доступных certificates - - name: string # Имя certificate - issuerRef: # IssuerRef references a properly configured ACME-type Issuer which should be used to create this Order. If the Issuer does not exist, processing will be retried. If the Issuer is not an 'ACME' Issuer, an error will be returned and the Order will be marked as failed. - name: string # Имя вызываемого ISSUER - isCa: bool # IsCA will request to mark the certificate as valid for certificate signing when submitting to the issuer. This will automatically add the `cert sign` usage to the list of `usages`. - ca: # Альтернатива блоку certificates.intermediate_ca - exportedKey: bool # запрашивать приватный ключ или нет - generate: bool # генерить ЦА или запросить существующий CA - spec: # блок описывающий certificate - subject: # блок описывающий принадлежность certificate - commonName: string # CommonName is the common name as specified on the DER encoded CSR. If specified, this value must also be present in `dnsNames` or `ipAddresses`. This field must match the corresponding field on the DER encoded CSR. - country: list of string # Countries to be used on the Certificate. - localite: list of string # Cities to be used on the Certificate. - organization: list of string # Organizations to be used on the Certificate. - organizationalUnit: list of string # Organizational Units to be used on the Certificate. - province: list of string # State/Provinces to be used on the Certificate. - postalCode: list of string # Postal codes to be used on the Certificate. - streetAddress: list of string # Street addresses to be used on the Certificate. - serialNumber: string # Serial number to be used on the Certificate - privateKey: # Options to control private keys used for the Certificate. - algorithm: string # Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either `RSA`,`Ed25519` or `ECDSA` If `algorithm` is specified and `size` is not provided, key size of 256 will be used for `ECDSA` key algorithm and key size of 2048 will be used for `RSA` key algorithm. key size is ignored when using the `Ed25519` key algorithm. - encoding: string # The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 and PKCS#8, respectively. Defaults to `PKCS1` if not specified. - size: integer # Size is the key bit size of the corresponding private key for this certificate. If `algorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified. If `algorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, and will default to `256` if not specified. If `algorithm` is set to `Ed25519`, Size is ignored. No other values are allowed. - hostnames: list of string # List of DNSNames that this solver will be used to solve. If specified and a match is found, a dnsNames selector will take precedence over a dnsZones selector. If multiple solvers match with the same dnsNames value, the solver with the most matching labels in matchLabels will be selected. If neither has more matches, the solver defined earlier in the list will be selected. - ipAddresses: - static: list of string - interfaces: list of string - dnsLookup: list of string - ttl: string # на какой промежуток времени заказывается сертификат - hostPath: string # путь, где будет размещен секрет по маске ${hostPathCert}/${certName} - withUpdate: bool - updateBefore: string # за сколько до истечения надо перевыпустить - trigger: list of list of string # список bash команд которые применятся после обновления сертификата - -secrets: # Описывает список доступных secrete - - name: # Имя secrete - issuerRef: # IssuerRef references a properly configured ACME-type Issuer which should be used to create this Order. If the Issuer does not exist, processing will be retried. If the Issuer is not an 'ACME' Issuer, an error will be returned and the Order will be marked as failed. - name: string # Имя вызываемого ISSUER - key: string - hostPath: string # путь, где будет размещен секрет по маске ${hostPathCert}/${keyName} diff --git a/example.yaml b/example.yaml deleted file mode 100644 index 03d0d99..0000000 --- a/example.yaml +++ /dev/null @@ -1,100 +0,0 @@ ---- -issuers: - - - name: kube-apiserver-sa - vault: - server: http://example.com:9200 - auth: - caBundle: - tlsInsecure: true - bootstrap: - token: ${token} - appRole: - name: kube-apiserver-sa - path: "clusters/cluster-1/approle" - secretIDLocalPath: /var/lib/key-keeper/vault/kube-apiserver-sa/secret-id - roleIDLocalPath: /var/lib/key-keeper/vault/kube-apiserver-sa/role-id - kv: - path: clusters/cluster-1/kv - timeout: 15s - - - name: kubernetes-ca - vault: - server: http://example.com:9200 - auth: - caBundle: - tlsInsecure: true - bootstrap: - token: ${token} - appRole: - name: kubernetes-ca - path: "clusters/cluster-1/approle" - secretIDLocalPath: /var/lib/key-keeper/vault/kubernetes-ca/secret-id - roleIDLocalPath: /var/lib/key-keeper/vault/kubernetes-ca/role-id - certificate: - CAPath: "clusters/cluster-1/pki/kubernetes" - rootCAPath: "clusters/cluster-1/pki/root" - timeout: 15s - - - name: kubelet-server - vault: - server: http://example.com:9200 - auth: - caBundle: - tlsInsecure: true - bootstrap: - token: hvs.Ouy9gdxmkEnBmYCVJQsYj1vA - appRole: - name: kubelet-server-ru-central1-a - path: "clusters/cluster-1/approle" - secretIDLocalPath: /var/lib/key-keeper/vault/kubelet-server/secret-id - roleIDLocalPath: /var/lib/key-keeper/vault/kubelet-server/role-id - certificate: - role: kubelet-server - CAPath: "clusters/cluster-1/pki/kubernetes" - timeout: 15s - - -certificates: - - - - name: kubernetes-ca - issuerRef: - name: kubernetes-ca - isCa: true - ca: - exportedKey: false - generate: false - hostPath: "/etc/kubernetes/pki/ca" - - - name: kubelet-server - issuerRef: - name: kubelet-server - spec: - subject: - commonName: "system:node:default.cluster-1.dobry-kot.ru" - usage: - - server auth - privateKey: - algorithm: "RSA" - encoding: "PKCS1" - size: 4096 - ipAddresses: - interfaces: - - lo - - eth* - ttl: 200h - hostnames: - - localhost - - "master-0.cluster-1.dobry-kot.ru" - renewBefore: 100h - hostPath: "/etc/kubernetes/pki/certs/kubelet" - - -secrets: - - - name: kube-apiserver-sa - issuerRef: - name: kube-apiserver-sa - key: public - hostPath: /etc/kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pub From 5df98372049d2d3d957e021cd601352dfc90144d Mon Sep 17 00:00:00 2001 From: fraima <107264732+fraima@users.noreply.github.com> Date: Thu, 29 Sep 2022 14:53:09 +0300 Subject: [PATCH 178/220] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7016394..d5366f9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -# key-keeper +### key-keeper - инструмент для linux хостов, позволяющий заказывать в Vault хранилище сертификаты и секреты и следить за их актуальностью. + ## Build & Push image From f344f6e8658347b8fb6e4a3e64fcc5bed9fc292e Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 29 Sep 2022 15:08:22 +0300 Subject: [PATCH 179/220] update --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d5366f9..7a57f45 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -### key-keeper - инструмент для linux хостов, позволяющий заказывать в Vault хранилище сертификаты и секреты и следить за их актуальностью. - +### key-keeper + инструмент для linux хостов, позволяющий заказывать в Vault хранилище сертификаты и секреты и следить за их актуальностью. ## Build & Push image From 33fa3085baafdc3d162c85b86470e15ae3ffb026 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 3 Oct 2022 16:18:01 +0300 Subject: [PATCH 180/220] add hostname --- internal/issuer/vault/certificate.go | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/internal/issuer/vault/certificate.go b/internal/issuer/vault/certificate.go index 1875b99..7c7fe6c 100644 --- a/internal/issuer/vault/certificate.go +++ b/internal/issuer/vault/certificate.go @@ -90,6 +90,12 @@ func createCSR(spec config.Spec) (crt, key []byte, err error) { return } + dnsNames, err := getDNSNames(spec.Hostnames) + if err != nil { + err = fmt.Errorf("get hostname: %w", err) + return + } + template := x509.CertificateRequest{ Subject: pkix.Name{ CommonName: spec.Subject.CommonName, @@ -103,7 +109,7 @@ func createCSR(spec config.Spec) (crt, key []byte, err error) { SerialNumber: spec.Subject.SerialNumber, }, IPAddresses: ips, - DNSNames: spec.Hostnames, + DNSNames: dnsNames, SignatureAlgorithm: x509.SHA256WithRSA, } @@ -185,6 +191,17 @@ func getIPAddresses(cfg config.IPAddresses) ([]net.IP, error) { return r, nil } +func getDNSNames(src []string) ([]string, error) { + var err error + for i, hostname := range src { + if hostname == "$HOSTNAME" { + src[i], err = os.Hostname() + break + } + } + return src, err +} + func inSlice(str string, sl []string) bool { for _, s := range sl { if regexp.MustCompile(s).MatchString(str) { From 90e6d6d7d6fb36b8e0a0c3d8ffff26bf17b05642 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 4 Oct 2022 13:19:46 +0300 Subject: [PATCH 181/220] fix --- internal/issuer/vault/utils.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/issuer/vault/utils.go b/internal/issuer/vault/utils.go index 53ba07c..9599062 100644 --- a/internal/issuer/vault/utils.go +++ b/internal/issuer/vault/utils.go @@ -18,8 +18,8 @@ func storeKeyPair(storePath string, name string, crt, key []byte) error { crtPath := path.Join(storePath, name+".pem") data, err := os.ReadFile(crtPath) if err != nil || !reflect.DeepEqual(crt, data) { - if err := os.WriteFile(path.Join(crtPath, name+".pem"), crt, 0644); err != nil { - return fmt.Errorf("failed to save certificate with path %s: %w", storePath, err) + if err := os.WriteFile(crtPath, crt, 0644); err != nil { + return fmt.Errorf("failed to save certificate with path: %w", err) } } } @@ -28,7 +28,7 @@ func storeKeyPair(storePath string, name string, crt, key []byte) error { keyPath := path.Join(storePath, name+"-key.pem") data, err := os.ReadFile(keyPath) if err != nil || !reflect.DeepEqual(key, data) { - if err := os.WriteFile(path.Join(storePath, name+"-key.pem"), key, 0600); err != nil { + if err := os.WriteFile(keyPath, key, 0600); err != nil { return fmt.Errorf("failed to save key file: %w", err) } } From 5206dbb7c5b1a7b23862473de98e88e5ab9901e1 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Wed, 5 Oct 2022 12:24:03 +0300 Subject: [PATCH 182/220] up --- internal/issuer/vault/utils.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/internal/issuer/vault/utils.go b/internal/issuer/vault/utils.go index 9599062..28a4695 100644 --- a/internal/issuer/vault/utils.go +++ b/internal/issuer/vault/utils.go @@ -9,13 +9,13 @@ import ( "reflect" ) -func storeKeyPair(storePath string, name string, crt, key []byte) error { - if err := os.MkdirAll(storePath, 0644); err != nil { - return fmt.Errorf("mkdir all %s : %w", storePath, err) +func storeKeyPair(filepath string, name string, crt, key []byte) error { + if err := os.MkdirAll(filepath, 0644); err != nil { + return fmt.Errorf("mkdir all %s : %w", filepath, err) } if crt != nil { - crtPath := path.Join(storePath, name+".pem") + crtPath := path.Join(filepath, name+".pem") data, err := os.ReadFile(crtPath) if err != nil || !reflect.DeepEqual(crt, data) { if err := os.WriteFile(crtPath, crt, 0644); err != nil { @@ -25,7 +25,7 @@ func storeKeyPair(storePath string, name string, crt, key []byte) error { } if key != nil { - keyPath := path.Join(storePath, name+"-key.pem") + keyPath := path.Join(filepath, name+"-key.pem") data, err := os.ReadFile(keyPath) if err != nil || !reflect.DeepEqual(key, data) { if err := os.WriteFile(keyPath, key, 0600); err != nil { @@ -36,8 +36,9 @@ func storeKeyPair(storePath string, name string, crt, key []byte) error { return nil } -func readCertificate(path string, name string) (*x509.Certificate, error) { - crt, err := os.ReadFile(path + "/" + name + ".pem") +func readCertificate(filepath string, name string) (*x509.Certificate, error) { + certPath := path.Join(filepath, name+".pem") + crt, err := os.ReadFile(certPath) if err != nil { return nil, err } From 84bcb355eb2432529d743429740bca330d9884d3 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 6 Oct 2022 14:52:57 +0300 Subject: [PATCH 183/220] update --- README.md | 19 ++- cmd/key-keeper/main.go | 5 +- internal/config/types.go | 22 ++-- internal/controller/controller.go | 15 ++- internal/issuer/vault/ca-certificate.go | 8 +- internal/issuer/vault/certificate.go | 4 +- .../{vault-auth.go => driver/driver-auth.go} | 10 +- internal/issuer/vault/driver/driver.go | 92 ++++++++++++++ internal/issuer/vault/driver/utils.go | 14 +++ internal/issuer/vault/resource.go | 35 ------ internal/issuer/vault/secret.go | 2 +- internal/issuer/vault/vault.go | 116 +++++++----------- 12 files changed, 193 insertions(+), 149 deletions(-) rename internal/issuer/vault/{vault-auth.go => driver/driver-auth.go} (89%) create mode 100644 internal/issuer/vault/driver/driver.go create mode 100644 internal/issuer/vault/driver/utils.go delete mode 100644 internal/issuer/vault/resource.go diff --git a/README.md b/README.md index 7a57f45..8f2d8c7 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ -### key-keeper - инструмент для linux хостов, позволяющий заказывать в Vault хранилище сертификаты и секреты и следить за их актуальностью. +### key-keeper + +инструмент для linux хостов, позволяющий заказывать в Vault хранилище сертификаты и секреты и следить за их актуальностью. ## Build & Push image @@ -31,6 +32,11 @@ key-keeper -config-dir /path/to/config-dir -config-regexp .*.conf --- issuers: - name: kubernetes-ca + role: kubelet-server + CAPath: "clusters/cluster-1/pki/kubernetes" + rootCAPath: "clusters/cluster-1/pki/root" + kv: + path: clusters/cluster-1/kv vault: server: http://example.com:9200 auth: @@ -42,14 +48,7 @@ issuers: name: kubernetes-ca path: "clusters/cluster-1/approle" secretIDLocalPath: /var/lib/key-keeper/vault/kubernetes-ca/secret-id - roleIDLocalPath: /var/lib/key-keeper/vault/kubernetes-ca/role-id - certificate: - role: kubelet-server - CAPath: "clusters/cluster-1/pki/kubernetes" - rootCAPath: "clusters/cluster-1/pki/root" - kv: - path: clusters/cluster-1/kv - timeout: 15s + roleIDLocalPath: /var/lib/key-keeper/vault/kubernetes-ca/role-idW certificates: - name: kubernetes-ca diff --git a/cmd/key-keeper/main.go b/cmd/key-keeper/main.go index 7f7831b..e053eaf 100644 --- a/cmd/key-keeper/main.go +++ b/cmd/key-keeper/main.go @@ -11,6 +11,7 @@ import ( "github.com/fraima/key-keeper/internal/config" "github.com/fraima/key-keeper/internal/controller" "github.com/fraima/key-keeper/internal/issuer/vault" + "github.com/fraima/key-keeper/internal/issuer/vault/driver" ) var ( @@ -48,7 +49,9 @@ func main() { cntl := controller.New( cfg.GetNewConfig, - vault.Connect, + vault.Connector( + driver.Connect, + ), ) if err := cntl.Start(); err != nil { diff --git a/internal/config/types.go b/internal/config/types.go index 2f0c2df..32c051a 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -8,8 +8,12 @@ type Config struct { } type Issuer struct { - Name string `yaml:"name"` - Vault Vault `yaml:"vault"` + Name string `yaml:"name"` + Role string `yaml:"role"` + CAPath string `yaml:"CAPath"` + RootCAPath string `yaml:"rootCAPath"` + KV KV `yaml:"kv"` + Vault Vault `yaml:"vault"` } type Resources struct { @@ -37,11 +41,9 @@ type Secret struct { } type Vault struct { - Server string `yaml:"server"` - Auth Auth `yaml:"auth"` - Certificate CertVault `yaml:"certificate"` - KV KV `yaml:"kv"` - Timeout time.Duration `yaml:"timeout"` + Server string `yaml:"server"` + Auth Auth `yaml:"auth"` + Timeout time.Duration `yaml:"timeout"` } type Auth struct { @@ -51,12 +53,6 @@ type Auth struct { AppRole AppRole `yaml:"appRole"` } -type CertVault struct { - Role string `yaml:"role"` - CAPath string `yaml:"CAPath"` - RootCAPath string `yaml:"rootCAPath"` -} - type Bootstrap struct { Token string `yaml:"token"` File string `yaml:"file"` diff --git a/internal/controller/controller.go b/internal/controller/controller.go index e80c339..9c381cb 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -11,13 +11,14 @@ import ( ) type Issuer interface { + Name() string AddResource(config.Resources) CheckResource() } type controller struct { getConfig func() (config.Config, error) - issuerConnector func(name string, cfg config.Vault) (Issuer, error) + issuerConnector func(cfg config.Issuer) (Issuer, error) issuer sync.Map } @@ -25,11 +26,11 @@ type controller struct { // New returns controller. func New( config func() (config.Config, error), - vaultConnector func(name string, cfg config.Vault) (Issuer, error), + issuerConnector func(cfg config.Issuer) (Issuer, error), ) *controller { return &controller{ getConfig: config, - issuerConnector: vaultConnector, + issuerConnector: issuerConnector, } } @@ -51,8 +52,12 @@ func (s *controller) Start() error { // start resource checking go func() { for range time.NewTicker(time.Hour).C { + s.issuer.Range(func(key, value any) bool { - value.(Issuer).CheckResource() + issuer := value.(Issuer) + zap.L().Debug("start_checking", zap.String("issuer", issuer.Name())) + issuer.CheckResource() + zap.L().Debug("finish_checking", zap.String("issuer", issuer.Name())) return true }) } @@ -79,7 +84,7 @@ func (s *controller) getNewResource() error { continue } - conn, err := s.issuerConnector(issuer.Name, issuer.Vault) + conn, err := s.issuerConnector(issuer) if err != nil { zap.L().Error("issuer_connect", zap.String("issuer_name", issuer.Name), zap.Error(err)) continue diff --git a/internal/issuer/vault/ca-certificate.go b/internal/issuer/vault/ca-certificate.go index b1473fd..1e364ea 100644 --- a/internal/issuer/vault/ca-certificate.go +++ b/internal/issuer/vault/ca-certificate.go @@ -65,7 +65,7 @@ func (s *vault) generateCA(cert config.Certificate) (crt, key []byte, err error) } vaultPath := path.Join(s.caPath, "intermediate/generate", keyType) - csr, err := s.Write(vaultPath, csrData) + csr, err := s.driver.Write(vaultPath, csrData) if err != nil { err = fmt.Errorf("generate: %w", err) return @@ -78,7 +78,7 @@ func (s *vault) generateCA(cert config.Certificate) (crt, key []byte, err error) } vaultPath = path.Join(s.rootCAPath, "root/sign-intermediate") - ica, err := s.Write(vaultPath, icaData) + ica, err := s.driver.Write(vaultPath, icaData) if err != nil { err = fmt.Errorf("send the intermediate ca CSR to the root CA for signing CA: %w", err) return @@ -89,7 +89,7 @@ func (s *vault) generateCA(cert config.Certificate) (crt, key []byte, err error) } vaultPath = path.Join(s.caPath, "intermediate/set-signed") - if _, err = s.Write(vaultPath, certData); err != nil { + if _, err = s.driver.Write(vaultPath, certData); err != nil { err = fmt.Errorf("publish the signed certificate back to the intermediate ca : %w", err) return } @@ -105,7 +105,7 @@ func (s *vault) generateCA(cert config.Certificate) (crt, key []byte, err error) func (s *vault) readCA(vaultPath string) (crt, key []byte, err error) { vaultPath = path.Join(vaultPath, "cert/ca_chain") - ica, err := s.Read(vaultPath) + ica, err := s.driver.Read(vaultPath) if ica != nil { if c, ok := ica["certificate"]; ok { crt = []byte(c.(string)) diff --git a/internal/issuer/vault/certificate.go b/internal/issuer/vault/certificate.go index 7c7fe6c..24c1d04 100644 --- a/internal/issuer/vault/certificate.go +++ b/internal/issuer/vault/certificate.go @@ -26,7 +26,7 @@ func (s *vault) checkCertificate(cert config.Certificate) { crt, err := readCertificate(cert.HostPath, cert.Name) if crt != nil { logger.Debug("ttl", zap.Float64("remaining time(h)", time.Until(crt.NotAfter).Hours())) - if time.Until(crt.NotAfter) < cert.UpdateBefore { + if time.Until(crt.NotAfter) <= cert.UpdateBefore { err = fmt.Errorf("expired until(h) %f", time.Until(crt.NotAfter).Hours()) } } @@ -65,7 +65,7 @@ func (s *vault) generateCertificate(certSpec config.Spec) ([]byte, []byte, error } vaultPath := path.Join(s.caPath, "sign", s.role) - cert, err := s.Write(vaultPath, certData) + cert, err := s.driver.Write(vaultPath, certData) if err != nil { return nil, nil, fmt.Errorf("generate with vault path %s : %w", vaultPath, err) } diff --git a/internal/issuer/vault/vault-auth.go b/internal/issuer/vault/driver/driver-auth.go similarity index 89% rename from internal/issuer/vault/vault-auth.go rename to internal/issuer/vault/driver/driver-auth.go index ab2f6fb..c70088a 100644 --- a/internal/issuer/vault/vault-auth.go +++ b/internal/issuer/vault/driver/driver-auth.go @@ -1,4 +1,4 @@ -package vault +package driver import ( "context" @@ -13,7 +13,7 @@ import ( "github.com/fraima/key-keeper/internal/config" ) -func (s *vault) auth(name string, a config.Auth) error { +func (s *driver) auth(name string, a config.Auth) error { roleID, err := s.roleID(name, a.AppRole) if err != nil { return fmt.Errorf("get role id: %w", err) @@ -52,7 +52,7 @@ func (s *vault) auth(name string, a config.Auth) error { return nil } -func (s *vault) roleID(name string, appRole config.AppRole) (string, error) { +func (s *driver) roleID(name string, appRole config.AppRole) (string, error) { if roleID, rErr := os.ReadFile(appRole.RoleIDLocalPath); rErr == nil { return string(roleID), nil } @@ -77,7 +77,7 @@ func (s *vault) roleID(name string, appRole config.AppRole) (string, error) { return roleID.(string), err } -func (s *vault) secretID(name string, appRole config.AppRole) (string, error) { +func (s *driver) secretID(name string, appRole config.AppRole) (string, error) { if secretID, rErr := os.ReadFile(appRole.SecretIDLocalPath); rErr == nil { return string(secretID), nil } @@ -102,7 +102,7 @@ func (s *vault) secretID(name string, appRole config.AppRole) (string, error) { return secretID.(string), err } -func (s *vault) updateAuthToken(appRoleAuth *auth.AppRoleAuth) (time.Duration, error) { +func (s *driver) updateAuthToken(appRoleAuth *auth.AppRoleAuth) (time.Duration, error) { authInfo, err := s.cli.Auth().Login(context.Background(), appRoleAuth) if err != nil { return 0, err diff --git a/internal/issuer/vault/driver/driver.go b/internal/issuer/vault/driver/driver.go new file mode 100644 index 0000000..64d9a71 --- /dev/null +++ b/internal/issuer/vault/driver/driver.go @@ -0,0 +1,92 @@ +package driver + +import ( + "context" + "fmt" + "net/http" + "os" + + "github.com/hashicorp/vault/api" + + "github.com/fraima/key-keeper/internal/config" + "github.com/fraima/key-keeper/internal/issuer/vault" +) + +type driver struct { + cli *api.Client +} + +// Connect to vault issuer. +func Connect(name string, cfg config.Vault) (vault.Driver, error) { + client, err := api.NewClient( + &api.Config{ + Address: cfg.Server, + HttpClient: &http.Client{ + Timeout: cfg.Timeout, + }, + }, + ) + if err != nil { + return nil, fmt.Errorf("new vault client: %w", err) + } + + token, err := getToken(cfg.Auth.Bootstrap) + if err != nil { + return nil, fmt.Errorf("get vault token: %w", err) + } + + client.SetToken(token) + if !cfg.Auth.TLSInsecure { + err = client.CloneConfig().ConfigureTLS(&api.TLSConfig{CACert: cfg.Auth.CABundle}) + if err != nil { + return nil, fmt.Errorf("configuring tls: %w", err) + } + } + + s := &driver{ + cli: client, + } + return s, s.auth(name, cfg.Auth) +} + +// Read secret from vault by path. +func (s *driver) Read(path string) (map[string]interface{}, error) { + sec, err := s.cli.Logical().Read(path) + if sec != nil { + return sec.Data, err + } + return nil, err +} + +// Write secret in vault by path. +func (s *driver) Write(path string, data map[string]interface{}) (map[string]interface{}, error) { + sec, err := s.cli.Logical().Write(path, data) + if sec != nil { + return sec.Data, err + } + return nil, err +} + +// Put in Vault KV. +func (s *driver) Put(kvMountPath, secretePath string, data map[string]interface{}) error { + _, err := s.cli.KVv2(kvMountPath).Put(context.Background(), secretePath, data) + return err +} + +// Get from Vault KV. +func (s *driver) Get(kvMountPath, secretePath string) (map[string]interface{}, error) { + sec, err := s.cli.KVv2(kvMountPath).Get(context.Background(), secretePath) + if sec != nil { + return sec.Data, err + } + return nil, err +} + +func getToken(b config.Bootstrap) (string, error) { + if b.Token != "" { + return b.Token, nil + } + + data, err := os.ReadFile(b.File) + return string(data), err +} diff --git a/internal/issuer/vault/driver/utils.go b/internal/issuer/vault/driver/utils.go new file mode 100644 index 0000000..3f1ece0 --- /dev/null +++ b/internal/issuer/vault/driver/utils.go @@ -0,0 +1,14 @@ +package driver + +import ( + "os" + "path" +) + +func writeToFile(filepath string, date []byte) error { + dir := path.Dir(filepath) + if err := os.MkdirAll(dir, os.ModePerm); err != nil { + return err + } + return os.WriteFile(filepath, date, 0644) +} diff --git a/internal/issuer/vault/resource.go b/internal/issuer/vault/resource.go deleted file mode 100644 index 5b27793..0000000 --- a/internal/issuer/vault/resource.go +++ /dev/null @@ -1,35 +0,0 @@ -package vault - -import ( - "go.uber.org/zap" - - "github.com/fraima/key-keeper/internal/config" -) - -func (s *vault) AddResource(r config.Resources) { - for _, cert := range r.Certificates { - s.certificate[cert.Name] = cert - } - for _, secret := range r.Secrets { - go func(secret config.Secret) { - s.checkSecret(secret) - }(secret) - } - s.CheckResource() -} - -func (s *vault) CheckResource() { - zap.L().Debug("checking") - - for _, cert := range s.certificate { - go func(c config.Certificate) { - if c.IsCA { - s.checkCA(c) - return - } - s.checkCertificate(c) - }(cert) - } - - zap.L().Debug("done") -} diff --git a/internal/issuer/vault/secret.go b/internal/issuer/vault/secret.go index 4dcc9e9..6b0e7e1 100644 --- a/internal/issuer/vault/secret.go +++ b/internal/issuer/vault/secret.go @@ -23,7 +23,7 @@ func (s *vault) checkSecret(i config.Secret) { } func (s *vault) readSecret(i config.Secret) ([]byte, error) { - storedSecrete, err := s.Get(s.kvMountPath, i.Name) + storedSecrete, err := s.driver.Get(s.kvMountPath, i.Name) if err != nil { return nil, fmt.Errorf("get from vault_kv : %w", err) } diff --git a/internal/issuer/vault/vault.go b/internal/issuer/vault/vault.go index 693fd39..53d26b8 100644 --- a/internal/issuer/vault/vault.go +++ b/internal/issuer/vault/vault.go @@ -1,20 +1,21 @@ package vault import ( - "context" - "fmt" - "net/http" - "os" - - "github.com/hashicorp/vault/api" - "github.com/fraima/key-keeper/internal/config" "github.com/fraima/key-keeper/internal/controller" ) +type Driver interface { + Read(path string) (map[string]interface{}, error) + Write(path string, data map[string]interface{}) (map[string]interface{}, error) + Put(kvMountPath, secretePath string, data map[string]interface{}) error + Get(kvMountPath, secretePath string) (map[string]interface{}, error) +} + type vault struct { - cli *api.Client + driver Driver + name string role string caPath string rootCAPath string @@ -23,84 +24,53 @@ type vault struct { certificate map[string]config.Certificate } -// Connect to vault issuer. -func Connect(name string, cfg config.Vault) (controller.Issuer, error) { - client, err := api.NewClient( - &api.Config{ - Address: cfg.Server, - HttpClient: &http.Client{ - Timeout: cfg.Timeout, - }, - }, - ) - if err != nil { - return nil, fmt.Errorf("new vault client: %w", err) - } - - token, err := getToken(cfg.Auth.Bootstrap) - if err != nil { - return nil, fmt.Errorf("get vault token: %w", err) - } - - client.SetToken(token) - if !cfg.Auth.TLSInsecure { - err = client.CloneConfig().ConfigureTLS(&api.TLSConfig{CACert: cfg.Auth.CABundle}) +func Connector( + connect func(name string, cfg config.Vault) (Driver, error), +) func(cfg config.Issuer) (controller.Issuer, error) { + return func(cfg config.Issuer) (controller.Issuer, error) { + driver, err := connect(cfg.Name, cfg.Vault) if err != nil { - return nil, fmt.Errorf("configuring tls: %w", err) + return nil, err } - } - s := &vault{ - cli: client, + return &vault{ + driver: driver, - role: cfg.Certificate.Role, - caPath: cfg.Certificate.CAPath, - rootCAPath: cfg.Certificate.RootCAPath, - kvMountPath: cfg.KV.Path, + name: cfg.Name, + role: cfg.Role, + caPath: cfg.CAPath, + rootCAPath: cfg.RootCAPath, + kvMountPath: cfg.KV.Path, - certificate: make(map[string]config.Certificate), + certificate: make(map[string]config.Certificate), + }, nil } - return s, s.auth(name, cfg.Auth) } -// Read secret from vault by path. -func (s *vault) Read(path string) (map[string]interface{}, error) { - sec, err := s.cli.Logical().Read(path) - if sec != nil { - return sec.Data, err - } - return nil, err +func (s *vault) Name() string { + return s.name } -// Write secret in vault by path. -func (s *vault) Write(path string, data map[string]interface{}) (map[string]interface{}, error) { - sec, err := s.cli.Logical().Write(path, data) - if sec != nil { - return sec.Data, err +func (s *vault) AddResource(r config.Resources) { + for _, cert := range r.Certificates { + s.certificate[cert.Name] = cert } - return nil, err -} - -// Put in Vault KV. -func (s *vault) Put(kvMountPath, secretePath string, data map[string]interface{}) error { - _, err := s.cli.KVv2(kvMountPath).Put(context.Background(), secretePath, data) - return err -} - -// Get from Vault KV. -func (s *vault) Get(kvMountPath, secretePath string) (map[string]interface{}, error) { - sec, err := s.cli.KVv2(kvMountPath).Get(context.Background(), secretePath) - if sec != nil { - return sec.Data, err + for _, secret := range r.Secrets { + go func(secret config.Secret) { + s.checkSecret(secret) + }(secret) } - return nil, err + s.CheckResource() } -func getToken(b config.Bootstrap) (string, error) { - if b.Token != "" { - return b.Token, nil +func (s *vault) CheckResource() { + for _, cert := range s.certificate { + go func(c config.Certificate) { + if c.IsCA { + s.checkCA(c) + return + } + s.checkCertificate(c) + }(cert) } - - data, err := os.ReadFile(b.File) - return string(data), err } From 5fc2537180fc052915fd83e4825108c98340f67b Mon Sep 17 00:00:00 2001 From: irbgeo Date: Fri, 7 Oct 2022 13:08:17 +0300 Subject: [PATCH 184/220] up secret config --- README.md | 4 ++-- internal/config/types.go | 2 +- internal/issuer/vault/secret.go | 2 +- internal/issuer/vault/vault.go | 18 ++++++++---------- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 8f2d8c7..1bd2762 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,6 @@ issuers: role: kubelet-server CAPath: "clusters/cluster-1/pki/kubernetes" rootCAPath: "clusters/cluster-1/pki/root" - kv: - path: clusters/cluster-1/kv vault: server: http://example.com:9200 auth: @@ -88,6 +86,8 @@ secrets: issuerRef: name: kube-apiserver-sa key: public + kv: + path: clusters/cluster-1/kv hostPath: /etc/kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pub ``` diff --git a/internal/config/types.go b/internal/config/types.go index 32c051a..752c598 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -12,7 +12,6 @@ type Issuer struct { Role string `yaml:"role"` CAPath string `yaml:"CAPath"` RootCAPath string `yaml:"rootCAPath"` - KV KV `yaml:"kv"` Vault Vault `yaml:"vault"` } @@ -38,6 +37,7 @@ type Secret struct { IssuerRef IssuerRef `yaml:"issuerRef"` Key string `yaml:"key"` HostPath string `yaml:"hostPath"` + KV KV `yaml:"kv"` } type Vault struct { diff --git a/internal/issuer/vault/secret.go b/internal/issuer/vault/secret.go index 6b0e7e1..e865b68 100644 --- a/internal/issuer/vault/secret.go +++ b/internal/issuer/vault/secret.go @@ -23,7 +23,7 @@ func (s *vault) checkSecret(i config.Secret) { } func (s *vault) readSecret(i config.Secret) ([]byte, error) { - storedSecrete, err := s.driver.Get(s.kvMountPath, i.Name) + storedSecrete, err := s.driver.Get(i.KV.Path, i.Name) if err != nil { return nil, fmt.Errorf("get from vault_kv : %w", err) } diff --git a/internal/issuer/vault/vault.go b/internal/issuer/vault/vault.go index 53d26b8..06882ab 100644 --- a/internal/issuer/vault/vault.go +++ b/internal/issuer/vault/vault.go @@ -15,11 +15,10 @@ type Driver interface { type vault struct { driver Driver - name string - role string - caPath string - rootCAPath string - kvMountPath string + name string + role string + caPath string + rootCAPath string certificate map[string]config.Certificate } @@ -36,11 +35,10 @@ func Connector( return &vault{ driver: driver, - name: cfg.Name, - role: cfg.Role, - caPath: cfg.CAPath, - rootCAPath: cfg.RootCAPath, - kvMountPath: cfg.KV.Path, + name: cfg.Name, + role: cfg.Role, + caPath: cfg.CAPath, + rootCAPath: cfg.RootCAPath, certificate: make(map[string]config.Certificate), }, nil From f30e2a1b6ef10833e053b93a97e80f5d00721609 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 10 Oct 2022 15:17:18 +0300 Subject: [PATCH 185/220] fix bootstrap token --- cmd/key-keeper/main.go | 4 +- internal/issuer/vault/ca-certificate.go | 8 +- internal/issuer/vault/certificate.go | 2 +- internal/issuer/vault/driver/driver-auth.go | 125 -------------------- internal/issuer/vault/driver/driver.go | 92 -------------- internal/issuer/vault/driver/utils.go | 14 --- internal/issuer/vault/secret.go | 5 +- internal/issuer/vault/vault.go | 8 +- 8 files changed, 13 insertions(+), 245 deletions(-) delete mode 100644 internal/issuer/vault/driver/driver-auth.go delete mode 100644 internal/issuer/vault/driver/driver.go delete mode 100644 internal/issuer/vault/driver/utils.go diff --git a/cmd/key-keeper/main.go b/cmd/key-keeper/main.go index e053eaf..9d5f4a3 100644 --- a/cmd/key-keeper/main.go +++ b/cmd/key-keeper/main.go @@ -11,7 +11,7 @@ import ( "github.com/fraima/key-keeper/internal/config" "github.com/fraima/key-keeper/internal/controller" "github.com/fraima/key-keeper/internal/issuer/vault" - "github.com/fraima/key-keeper/internal/issuer/vault/driver" + "github.com/fraima/key-keeper/internal/issuer/vault/client" ) var ( @@ -50,7 +50,7 @@ func main() { cntl := controller.New( cfg.GetNewConfig, vault.Connector( - driver.Connect, + client.Connect, ), ) diff --git a/internal/issuer/vault/ca-certificate.go b/internal/issuer/vault/ca-certificate.go index 1e364ea..8291eb7 100644 --- a/internal/issuer/vault/ca-certificate.go +++ b/internal/issuer/vault/ca-certificate.go @@ -65,7 +65,7 @@ func (s *vault) generateCA(cert config.Certificate) (crt, key []byte, err error) } vaultPath := path.Join(s.caPath, "intermediate/generate", keyType) - csr, err := s.driver.Write(vaultPath, csrData) + csr, err := s.cli.Write(vaultPath, csrData) if err != nil { err = fmt.Errorf("generate: %w", err) return @@ -78,7 +78,7 @@ func (s *vault) generateCA(cert config.Certificate) (crt, key []byte, err error) } vaultPath = path.Join(s.rootCAPath, "root/sign-intermediate") - ica, err := s.driver.Write(vaultPath, icaData) + ica, err := s.cli.Write(vaultPath, icaData) if err != nil { err = fmt.Errorf("send the intermediate ca CSR to the root CA for signing CA: %w", err) return @@ -89,7 +89,7 @@ func (s *vault) generateCA(cert config.Certificate) (crt, key []byte, err error) } vaultPath = path.Join(s.caPath, "intermediate/set-signed") - if _, err = s.driver.Write(vaultPath, certData); err != nil { + if _, err = s.cli.Write(vaultPath, certData); err != nil { err = fmt.Errorf("publish the signed certificate back to the intermediate ca : %w", err) return } @@ -105,7 +105,7 @@ func (s *vault) generateCA(cert config.Certificate) (crt, key []byte, err error) func (s *vault) readCA(vaultPath string) (crt, key []byte, err error) { vaultPath = path.Join(vaultPath, "cert/ca_chain") - ica, err := s.driver.Read(vaultPath) + ica, err := s.cli.Read(vaultPath) if ica != nil { if c, ok := ica["certificate"]; ok { crt = []byte(c.(string)) diff --git a/internal/issuer/vault/certificate.go b/internal/issuer/vault/certificate.go index 24c1d04..26ddbd1 100644 --- a/internal/issuer/vault/certificate.go +++ b/internal/issuer/vault/certificate.go @@ -65,7 +65,7 @@ func (s *vault) generateCertificate(certSpec config.Spec) ([]byte, []byte, error } vaultPath := path.Join(s.caPath, "sign", s.role) - cert, err := s.driver.Write(vaultPath, certData) + cert, err := s.cli.Write(vaultPath, certData) if err != nil { return nil, nil, fmt.Errorf("generate with vault path %s : %w", vaultPath, err) } diff --git a/internal/issuer/vault/driver/driver-auth.go b/internal/issuer/vault/driver/driver-auth.go deleted file mode 100644 index c70088a..0000000 --- a/internal/issuer/vault/driver/driver-auth.go +++ /dev/null @@ -1,125 +0,0 @@ -package driver - -import ( - "context" - "fmt" - "os" - "path" - "time" - - auth "github.com/hashicorp/vault/api/auth/approle" - "go.uber.org/zap" - - "github.com/fraima/key-keeper/internal/config" -) - -func (s *driver) auth(name string, a config.Auth) error { - roleID, err := s.roleID(name, a.AppRole) - if err != nil { - return fmt.Errorf("get role id: %w", err) - } - secretID, err := s.secretID(name, a.AppRole) - if err != nil { - return fmt.Errorf("get secret id: %w", err) - } - - appRoleAuth, err := auth.NewAppRoleAuth( - roleID, - &auth.SecretID{ - FromString: secretID, - }, - auth.WithMountPath(a.AppRole.Path), - ) - if err != nil { - return err - } - - ttl, err := s.updateAuthToken(appRoleAuth) - if err != nil { - return err - } - - go func() { - t := time.NewTimer(ttl / 2) - for range t.C { - ttl, err := s.updateAuthToken(appRoleAuth) - if err != nil { - zap.L().Error("update auth token", zap.String("issuer_name", name), zap.Error(err)) - } - t.Reset(ttl / 2) - } - }() - return nil -} - -func (s *driver) roleID(name string, appRole config.AppRole) (string, error) { - if roleID, rErr := os.ReadFile(appRole.RoleIDLocalPath); rErr == nil { - return string(roleID), nil - } - - vaultPath := path.Join("auth", appRole.Path, "role", appRole.Name, "role-id") - role, err := s.Read(vaultPath) - if err != nil { - return "", fmt.Errorf("read role_id for path: %s : %w", vaultPath, err) - } - if role == nil { - return "", fmt.Errorf("no role_id info was returned") - } - - roleID, ok := role["role_id"] - if !ok { - return "", fmt.Errorf("not found role_id") - } - - if err = writeToFile(appRole.RoleIDLocalPath, []byte(roleID.(string))); err != nil { - return "", fmt.Errorf("save role id path: %s : %w", appRole.RoleIDLocalPath, err) - } - return roleID.(string), err -} - -func (s *driver) secretID(name string, appRole config.AppRole) (string, error) { - if secretID, rErr := os.ReadFile(appRole.SecretIDLocalPath); rErr == nil { - return string(secretID), nil - } - - vaultPath := path.Join("auth", appRole.Path, "role", appRole.Name, "secret-id") - secret, err := s.Write(vaultPath, nil) - if err != nil { - return "", fmt.Errorf("read secrete_id for path: %s : %w", vaultPath, err) - } - if secret == nil { - return "", fmt.Errorf("no secrete_id info was returned") - } - - secretID, ok := secret["secret_id"] - if !ok { - return "", fmt.Errorf("not found secrete_id") - } - - if err = writeToFile(appRole.SecretIDLocalPath, []byte(secretID.(string))); err != nil { - return "", fmt.Errorf("save secret id path: %s : %w", appRole.SecretIDLocalPath, err) - } - return secretID.(string), err -} - -func (s *driver) updateAuthToken(appRoleAuth *auth.AppRoleAuth) (time.Duration, error) { - authInfo, err := s.cli.Auth().Login(context.Background(), appRoleAuth) - if err != nil { - return 0, err - } - if authInfo == nil { - return 0, fmt.Errorf("no auth info was returned after login") - } - - token, err := authInfo.TokenID() - if err != nil { - return 0, err - } - s.cli.SetToken(token) - - ttl, err := authInfo.TokenTTL() - if err != nil { - return 0, err - } - return ttl, nil -} diff --git a/internal/issuer/vault/driver/driver.go b/internal/issuer/vault/driver/driver.go deleted file mode 100644 index 64d9a71..0000000 --- a/internal/issuer/vault/driver/driver.go +++ /dev/null @@ -1,92 +0,0 @@ -package driver - -import ( - "context" - "fmt" - "net/http" - "os" - - "github.com/hashicorp/vault/api" - - "github.com/fraima/key-keeper/internal/config" - "github.com/fraima/key-keeper/internal/issuer/vault" -) - -type driver struct { - cli *api.Client -} - -// Connect to vault issuer. -func Connect(name string, cfg config.Vault) (vault.Driver, error) { - client, err := api.NewClient( - &api.Config{ - Address: cfg.Server, - HttpClient: &http.Client{ - Timeout: cfg.Timeout, - }, - }, - ) - if err != nil { - return nil, fmt.Errorf("new vault client: %w", err) - } - - token, err := getToken(cfg.Auth.Bootstrap) - if err != nil { - return nil, fmt.Errorf("get vault token: %w", err) - } - - client.SetToken(token) - if !cfg.Auth.TLSInsecure { - err = client.CloneConfig().ConfigureTLS(&api.TLSConfig{CACert: cfg.Auth.CABundle}) - if err != nil { - return nil, fmt.Errorf("configuring tls: %w", err) - } - } - - s := &driver{ - cli: client, - } - return s, s.auth(name, cfg.Auth) -} - -// Read secret from vault by path. -func (s *driver) Read(path string) (map[string]interface{}, error) { - sec, err := s.cli.Logical().Read(path) - if sec != nil { - return sec.Data, err - } - return nil, err -} - -// Write secret in vault by path. -func (s *driver) Write(path string, data map[string]interface{}) (map[string]interface{}, error) { - sec, err := s.cli.Logical().Write(path, data) - if sec != nil { - return sec.Data, err - } - return nil, err -} - -// Put in Vault KV. -func (s *driver) Put(kvMountPath, secretePath string, data map[string]interface{}) error { - _, err := s.cli.KVv2(kvMountPath).Put(context.Background(), secretePath, data) - return err -} - -// Get from Vault KV. -func (s *driver) Get(kvMountPath, secretePath string) (map[string]interface{}, error) { - sec, err := s.cli.KVv2(kvMountPath).Get(context.Background(), secretePath) - if sec != nil { - return sec.Data, err - } - return nil, err -} - -func getToken(b config.Bootstrap) (string, error) { - if b.Token != "" { - return b.Token, nil - } - - data, err := os.ReadFile(b.File) - return string(data), err -} diff --git a/internal/issuer/vault/driver/utils.go b/internal/issuer/vault/driver/utils.go deleted file mode 100644 index 3f1ece0..0000000 --- a/internal/issuer/vault/driver/utils.go +++ /dev/null @@ -1,14 +0,0 @@ -package driver - -import ( - "os" - "path" -) - -func writeToFile(filepath string, date []byte) error { - dir := path.Dir(filepath) - if err := os.MkdirAll(dir, os.ModePerm); err != nil { - return err - } - return os.WriteFile(filepath, date, 0644) -} diff --git a/internal/issuer/vault/secret.go b/internal/issuer/vault/secret.go index e865b68..89831c9 100644 --- a/internal/issuer/vault/secret.go +++ b/internal/issuer/vault/secret.go @@ -16,14 +16,13 @@ func (s *vault) checkSecret(i config.Secret) { logger.Warn("read", zap.Error(err)) } - err = writeToFile(i.HostPath, secret) - if err != nil { + if err = writeToFile(i.HostPath, secret); err != nil { zap.L().Error("store", zap.String("path", i.HostPath), zap.Error(err)) } } func (s *vault) readSecret(i config.Secret) ([]byte, error) { - storedSecrete, err := s.driver.Get(i.KV.Path, i.Name) + storedSecrete, err := s.cli.Get(i.KV.Path, i.Name) if err != nil { return nil, fmt.Errorf("get from vault_kv : %w", err) } diff --git a/internal/issuer/vault/vault.go b/internal/issuer/vault/vault.go index 06882ab..81211e8 100644 --- a/internal/issuer/vault/vault.go +++ b/internal/issuer/vault/vault.go @@ -5,7 +5,7 @@ import ( "github.com/fraima/key-keeper/internal/controller" ) -type Driver interface { +type Client interface { Read(path string) (map[string]interface{}, error) Write(path string, data map[string]interface{}) (map[string]interface{}, error) Put(kvMountPath, secretePath string, data map[string]interface{}) error @@ -13,7 +13,7 @@ type Driver interface { } type vault struct { - driver Driver + cli Client name string role string @@ -24,7 +24,7 @@ type vault struct { } func Connector( - connect func(name string, cfg config.Vault) (Driver, error), + connect func(name string, cfg config.Vault) (Client, error), ) func(cfg config.Issuer) (controller.Issuer, error) { return func(cfg config.Issuer) (controller.Issuer, error) { driver, err := connect(cfg.Name, cfg.Vault) @@ -33,7 +33,7 @@ func Connector( } return &vault{ - driver: driver, + cli: driver, name: cfg.Name, role: cfg.Role, From dc0095fefe0ad2534c0749a9eb83eec287bf81d3 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 10 Oct 2022 15:22:45 +0300 Subject: [PATCH 186/220] fix bootstrap token --- internal/issuer/vault/client/auth.go | 125 +++++++++++++++++++++++++ internal/issuer/vault/client/client.go | 93 ++++++++++++++++++ internal/issuer/vault/client/utils.go | 14 +++ 3 files changed, 232 insertions(+) create mode 100644 internal/issuer/vault/client/auth.go create mode 100644 internal/issuer/vault/client/client.go create mode 100644 internal/issuer/vault/client/utils.go diff --git a/internal/issuer/vault/client/auth.go b/internal/issuer/vault/client/auth.go new file mode 100644 index 0000000..45767eb --- /dev/null +++ b/internal/issuer/vault/client/auth.go @@ -0,0 +1,125 @@ +package client + +import ( + "context" + "fmt" + "os" + "path" + "time" + + auth "github.com/hashicorp/vault/api/auth/approle" + "go.uber.org/zap" + + "github.com/fraima/key-keeper/internal/config" +) + +func (s *client) auth(name string, a config.Auth) error { + roleID, err := s.roleID(name, a.AppRole) + if err != nil { + return fmt.Errorf("get role id: %w", err) + } + secretID, err := s.secretID(name, a.AppRole) + if err != nil { + return fmt.Errorf("get secret id: %w", err) + } + + appRoleAuth, err := auth.NewAppRoleAuth( + roleID, + &auth.SecretID{ + FromString: secretID, + }, + auth.WithMountPath(a.AppRole.Path), + ) + if err != nil { + return err + } + + ttl, err := s.updateAuthToken(appRoleAuth) + if err != nil { + return err + } + + go func() { + t := time.NewTimer(ttl / 2) + for range t.C { + ttl, err := s.updateAuthToken(appRoleAuth) + if err != nil { + zap.L().Error("update auth token", zap.String("issuer_name", name), zap.Error(err)) + } + t.Reset(ttl / 2) + } + }() + return nil +} + +func (s *client) roleID(name string, appRole config.AppRole) (string, error) { + if roleID, rErr := os.ReadFile(appRole.RoleIDLocalPath); rErr == nil { + return string(roleID), nil + } + + vaultPath := path.Join("auth", appRole.Path, "role", appRole.Name, "role-id") + role, err := s.Read(vaultPath) + if err != nil { + return "", fmt.Errorf("read role_id for path: %s : %w", vaultPath, err) + } + if role == nil { + return "", fmt.Errorf("no role_id info was returned") + } + + roleID, ok := role["role_id"] + if !ok { + return "", fmt.Errorf("not found role_id") + } + + if err = writeToFile(appRole.RoleIDLocalPath, []byte(roleID.(string))); err != nil { + return "", fmt.Errorf("save role id path: %s : %w", appRole.RoleIDLocalPath, err) + } + return roleID.(string), err +} + +func (s *client) secretID(name string, appRole config.AppRole) (string, error) { + if secretID, rErr := os.ReadFile(appRole.SecretIDLocalPath); rErr == nil { + return string(secretID), nil + } + + vaultPath := path.Join("auth", appRole.Path, "role", appRole.Name, "secret-id") + secret, err := s.Write(vaultPath, nil) + if err != nil { + return "", fmt.Errorf("read secrete_id for path: %s : %w", vaultPath, err) + } + if secret == nil { + return "", fmt.Errorf("no secrete_id info was returned") + } + + secretID, ok := secret["secret_id"] + if !ok { + return "", fmt.Errorf("not found secrete_id") + } + + if err = writeToFile(appRole.SecretIDLocalPath, []byte(secretID.(string))); err != nil { + return "", fmt.Errorf("save secret id path: %s : %w", appRole.SecretIDLocalPath, err) + } + return secretID.(string), err +} + +func (s *client) updateAuthToken(appRoleAuth *auth.AppRoleAuth) (time.Duration, error) { + authInfo, err := s.cli.Auth().Login(context.Background(), appRoleAuth) + if err != nil { + return 0, err + } + if authInfo == nil { + return 0, fmt.Errorf("no auth info was returned after login") + } + + token, err := authInfo.TokenID() + if err != nil { + return 0, err + } + s.cli.SetToken(token) + + ttl, err := authInfo.TokenTTL() + if err != nil { + return 0, err + } + return ttl, nil +} diff --git a/internal/issuer/vault/client/client.go b/internal/issuer/vault/client/client.go new file mode 100644 index 0000000..0d56d8a --- /dev/null +++ b/internal/issuer/vault/client/client.go @@ -0,0 +1,93 @@ +package client + +import ( + "context" + "fmt" + "net/http" + "os" + "strings" + + "github.com/hashicorp/vault/api" + + "github.com/fraima/key-keeper/internal/config" + "github.com/fraima/key-keeper/internal/issuer/vault" +) + +type client struct { + cli *api.Client +} + +// Connect to vault issuer. +func Connect(name string, cfg config.Vault) (vault.Client, error) { + cli, err := api.NewClient( + &api.Config{ + Address: cfg.Server, + HttpClient: &http.Client{ + Timeout: cfg.Timeout, + }, + }, + ) + if err != nil { + return nil, fmt.Errorf("new vault client: %w", err) + } + + token, err := getToken(cfg.Auth.Bootstrap) + if err != nil { + return nil, fmt.Errorf("get vault token: %w", err) + } + + cli.SetToken(token) + if !cfg.Auth.TLSInsecure { + err = cli.CloneConfig().ConfigureTLS(&api.TLSConfig{CACert: cfg.Auth.CABundle}) + if err != nil { + return nil, fmt.Errorf("configuring tls: %w", err) + } + } + + s := &client{ + cli: cli, + } + return s, s.auth(name, cfg.Auth) +} + +// Read secret from vault by path. +func (s *client) Read(path string) (map[string]interface{}, error) { + sec, err := s.cli.Logical().Read(path) + if sec != nil { + return sec.Data, err + } + return nil, err +} + +// Write secret in vault by path. +func (s *client) Write(path string, data map[string]interface{}) (map[string]interface{}, error) { + sec, err := s.cli.Logical().Write(path, data) + if sec != nil { + return sec.Data, err + } + return nil, err +} + +// Put in Vault KV. +func (s *client) Put(kvMountPath, secretePath string, data map[string]interface{}) error { + _, err := s.cli.KVv2(kvMountPath).Put(context.Background(), secretePath, data) + return err +} + +// Get from Vault KV. +func (s *client) Get(kvMountPath, secretePath string) (map[string]interface{}, error) { + sec, err := s.cli.KVv2(kvMountPath).Get(context.Background(), secretePath) + if sec != nil { + return sec.Data, err + } + return nil, err +} + +func getToken(b config.Bootstrap) (string, error) { + if b.Token != "" { + return b.Token, nil + } + + data, err := os.ReadFile(b.File) + return strings.TrimSuffix(string(data), "\n"), err +} diff --git a/internal/issuer/vault/client/utils.go b/internal/issuer/vault/client/utils.go new file mode 100644 index 0000000..96fe9fb --- /dev/null +++ b/internal/issuer/vault/client/utils.go @@ -0,0 +1,14 @@ +package client + +import ( + "os" + "path" +) + +func writeToFile(filepath string, date []byte) error { + dir := path.Dir(filepath) + if err := os.MkdirAll(dir, os.ModePerm); err != nil { + return err + } + return os.WriteFile(filepath, date, 0644) +} From 58850a86db33b8a741c0f905c79c0bd88e9ed2cd Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 10 Oct 2022 15:48:31 +0300 Subject: [PATCH 187/220] cfg up --- README.md | 7 ++++--- internal/config/types.go | 19 +++++++++++-------- internal/issuer/vault/client/client.go | 3 ++- internal/issuer/vault/vault.go | 6 +++--- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 1bd2762..e0803c7 100644 --- a/README.md +++ b/README.md @@ -32,9 +32,6 @@ key-keeper -config-dir /path/to/config-dir -config-regexp .*.conf --- issuers: - name: kubernetes-ca - role: kubelet-server - CAPath: "clusters/cluster-1/pki/kubernetes" - rootCAPath: "clusters/cluster-1/pki/root" vault: server: http://example.com:9200 auth: @@ -47,6 +44,10 @@ issuers: path: "clusters/cluster-1/approle" secretIDLocalPath: /var/lib/key-keeper/vault/kubernetes-ca/secret-id roleIDLocalPath: /var/lib/key-keeper/vault/kubernetes-ca/role-idW + certificate: + role: kubelet-server + CAPath: "clusters/cluster-1/pki/kubernetes" + rootCAPath: "clusters/cluster-1/pki/root" certificates: - name: kubernetes-ca diff --git a/internal/config/types.go b/internal/config/types.go index 752c598..c80cca8 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -8,11 +8,8 @@ type Config struct { } type Issuer struct { - Name string `yaml:"name"` - Role string `yaml:"role"` - CAPath string `yaml:"CAPath"` - RootCAPath string `yaml:"rootCAPath"` - Vault Vault `yaml:"vault"` + Name string `yaml:"name"` + Vault Vault `yaml:"vault"` } type Resources struct { @@ -41,9 +38,9 @@ type Secret struct { } type Vault struct { - Server string `yaml:"server"` - Auth Auth `yaml:"auth"` - Timeout time.Duration `yaml:"timeout"` + Server string `yaml:"server"` + Auth Auth `yaml:"auth"` + Certificate VaultCert `yaml:"auth"` } type Auth struct { @@ -65,6 +62,12 @@ type AppRole struct { SecretIDLocalPath string `yaml:"secretIDLocalPath"` } +type VaultCert struct { + Role string `yaml:"role"` + CAPath string `yaml:"CAPath"` + RootCAPath string `yaml:"rootCAPath"` +} + type KV struct { Path string `yaml:"path"` } diff --git a/internal/issuer/vault/client/client.go b/internal/issuer/vault/client/client.go index 0d56d8a..209c19e 100644 --- a/internal/issuer/vault/client/client.go +++ b/internal/issuer/vault/client/client.go @@ -6,6 +6,7 @@ import ( "net/http" "os" "strings" + "time" "github.com/hashicorp/vault/api" @@ -23,7 +24,7 @@ func Connect(name string, cfg config.Vault) (vault.Client, error) { &api.Config{ Address: cfg.Server, HttpClient: &http.Client{ - Timeout: cfg.Timeout, + Timeout: 10 *time.Second, }, }, ) diff --git a/internal/issuer/vault/vault.go b/internal/issuer/vault/vault.go index 81211e8..352ce12 100644 --- a/internal/issuer/vault/vault.go +++ b/internal/issuer/vault/vault.go @@ -36,9 +36,9 @@ func Connector( cli: driver, name: cfg.Name, - role: cfg.Role, - caPath: cfg.CAPath, - rootCAPath: cfg.RootCAPath, + role: cfg.Vault.Certificate.Role, + caPath: cfg.Vault.Certificate.CAPath, + rootCAPath: cfg.Vault.Certificate.RootCAPath, certificate: make(map[string]config.Certificate), }, nil From f93aa5d13181c1b9f5afc2fe9aaa208db7452cde Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 10 Oct 2022 16:07:40 +0300 Subject: [PATCH 188/220] update --- README.md | 2 +- internal/config/types.go | 8 ++++---- internal/issuer/vault/vault.go | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index e0803c7..eabc1fe 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ issuers: path: "clusters/cluster-1/approle" secretIDLocalPath: /var/lib/key-keeper/vault/kubernetes-ca/secret-id roleIDLocalPath: /var/lib/key-keeper/vault/kubernetes-ca/role-idW - certificate: + resource: role: kubelet-server CAPath: "clusters/cluster-1/pki/kubernetes" rootCAPath: "clusters/cluster-1/pki/root" diff --git a/internal/config/types.go b/internal/config/types.go index c80cca8..64a5562 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -38,9 +38,9 @@ type Secret struct { } type Vault struct { - Server string `yaml:"server"` - Auth Auth `yaml:"auth"` - Certificate VaultCert `yaml:"auth"` + Server string `yaml:"server"` + Auth Auth `yaml:"auth"` + Resource Resource `yaml:"resource"` } type Auth struct { @@ -62,7 +62,7 @@ type AppRole struct { SecretIDLocalPath string `yaml:"secretIDLocalPath"` } -type VaultCert struct { +type Resource struct { Role string `yaml:"role"` CAPath string `yaml:"CAPath"` RootCAPath string `yaml:"rootCAPath"` diff --git a/internal/issuer/vault/vault.go b/internal/issuer/vault/vault.go index 352ce12..0506afd 100644 --- a/internal/issuer/vault/vault.go +++ b/internal/issuer/vault/vault.go @@ -36,9 +36,9 @@ func Connector( cli: driver, name: cfg.Name, - role: cfg.Vault.Certificate.Role, - caPath: cfg.Vault.Certificate.CAPath, - rootCAPath: cfg.Vault.Certificate.RootCAPath, + role: cfg.Vault.Resource.Role, + caPath: cfg.Vault.Resource.CAPath, + rootCAPath: cfg.Vault.Resource.RootCAPath, certificate: make(map[string]config.Certificate), }, nil From 7fe15d7ddc29325726cd35a269733dc528b8c435 Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Mon, 10 Oct 2022 16:20:02 +0300 Subject: [PATCH 189/220] =?UTF-8?q?=D0=9F=D0=BE=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D1=8F=D0=B5=D1=82=20=D1=87=D0=B5=D0=BA=20=D0=B8=D0=BD?= =?UTF-8?q?=D1=82=D0=B5=D1=80=D0=B2=D0=B0=D0=BB=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D1=81=D0=B5=D1=80=D1=82=D0=B8=D1=84=D0=B8=D0=BA=D0=B0=D1=82?= =?UTF-8?q?=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/controller/controller.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 9c381cb..14c49e6 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -51,7 +51,7 @@ func (s *controller) Start() error { // start resource checking go func() { - for range time.NewTicker(time.Hour).C { + for range time.NewTicker(30 * time.Second).C { s.issuer.Range(func(key, value any) bool { issuer := value.(Issuer) From 8836250e871f62e39e59411612dfd2fa5fc18a88 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 10 Oct 2022 16:29:27 +0300 Subject: [PATCH 190/220] up --- README.md | 4 ++-- internal/config/types.go | 2 +- internal/issuer/vault/secret.go | 2 +- internal/issuer/vault/vault.go | 2 ++ 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index eabc1fe..8619289 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,8 @@ issuers: role: kubelet-server CAPath: "clusters/cluster-1/pki/kubernetes" rootCAPath: "clusters/cluster-1/pki/root" + kv: + path: clusters/cluster-1/kv certificates: - name: kubernetes-ca @@ -87,8 +89,6 @@ secrets: issuerRef: name: kube-apiserver-sa key: public - kv: - path: clusters/cluster-1/kv hostPath: /etc/kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pub ``` diff --git a/internal/config/types.go b/internal/config/types.go index 64a5562..6f44352 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -34,7 +34,6 @@ type Secret struct { IssuerRef IssuerRef `yaml:"issuerRef"` Key string `yaml:"key"` HostPath string `yaml:"hostPath"` - KV KV `yaml:"kv"` } type Vault struct { @@ -66,6 +65,7 @@ type Resource struct { Role string `yaml:"role"` CAPath string `yaml:"CAPath"` RootCAPath string `yaml:"rootCAPath"` + KV KV `yaml:"kv"` } type KV struct { diff --git a/internal/issuer/vault/secret.go b/internal/issuer/vault/secret.go index 89831c9..93bb189 100644 --- a/internal/issuer/vault/secret.go +++ b/internal/issuer/vault/secret.go @@ -22,7 +22,7 @@ func (s *vault) checkSecret(i config.Secret) { } func (s *vault) readSecret(i config.Secret) ([]byte, error) { - storedSecrete, err := s.cli.Get(i.KV.Path, i.Name) + storedSecrete, err := s.cli.Get(s.kv, i.Name) if err != nil { return nil, fmt.Errorf("get from vault_kv : %w", err) } diff --git a/internal/issuer/vault/vault.go b/internal/issuer/vault/vault.go index 0506afd..6aed08a 100644 --- a/internal/issuer/vault/vault.go +++ b/internal/issuer/vault/vault.go @@ -19,6 +19,7 @@ type vault struct { role string caPath string rootCAPath string + kv string certificate map[string]config.Certificate } @@ -39,6 +40,7 @@ func Connector( role: cfg.Vault.Resource.Role, caPath: cfg.Vault.Resource.CAPath, rootCAPath: cfg.Vault.Resource.RootCAPath, + kv: cfg.Vault.Resource.KV.Path, certificate: make(map[string]config.Certificate), }, nil From 7318df41cace72cb42aead5e2aebe3bcc70c8dcf Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Mon, 10 Oct 2022 17:07:13 +0300 Subject: [PATCH 191/220] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=BE=20=D0=BE=D0=BF=D0=B8=D1=81=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=82=D1=83=D1=80?= =?UTF-8?q?=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 139 +++++++++++++++++++++++++++++------------------------- 1 file changed, 74 insertions(+), 65 deletions(-) diff --git a/README.md b/README.md index eabc1fe..b17743b 100644 --- a/README.md +++ b/README.md @@ -28,69 +28,8 @@ key-keeper -config-dir /path/to/config-dir -config-regexp .*.conf ## Пример конфига -```yaml ---- -issuers: - - name: kubernetes-ca - vault: - server: http://example.com:9200 - auth: - caBundle: - tlsInsecure: true - bootstrap: - token: ${token} - appRole: - name: kubernetes-ca - path: "clusters/cluster-1/approle" - secretIDLocalPath: /var/lib/key-keeper/vault/kubernetes-ca/secret-id - roleIDLocalPath: /var/lib/key-keeper/vault/kubernetes-ca/role-idW - resource: - role: kubelet-server - CAPath: "clusters/cluster-1/pki/kubernetes" - rootCAPath: "clusters/cluster-1/pki/root" -certificates: - - name: kubernetes-ca - issuerRef: - name: kubernetes-ca - isCa: true - ca: - exportedKey: false - generate: false - hostPath: "/etc/kubernetes/pki/ca" - - name: kubelet-server - issuerRef: - name: kubelet-server - spec: - subject: - commonName: "system:node:master-0.cluster-1.dobry-kot.ru" - usage: - - server auth - privateKey: - algorithm: "RSA" - encoding: "PKCS1" - size: 4096 - ipAddresses: - interfaces: - - lo - - eth* - ttl: 200h - hostnames: - - localhost - - "master-0.cluster-1.dobry-kot.ru" - renewBefore: 100h - hostPath: "/etc/kubernetes/pki/certs/kubelet" - -secrets: - - name: kube-apiserver-sa - issuerRef: - name: kube-apiserver-sa - key: public - kv: - path: clusters/cluster-1/kv - hostPath: /etc/kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pub -``` ## Описание структуры конфигов: @@ -113,12 +52,35 @@ secrets: | `.vault.auth.appRole.secretIDLocalPath` | string | локальный путь, где будет искать secret_id для авторизации | | `.vault.kv` | object | описание доступа в Vault к Key Value стореджу | | `.vault.kv.path` | string | путь в Vault до Key Value стореджа | -| `.vault.certificate` | object | инструция доступа к vault роли для выпуска сертификата | -| `.vault.certificate.role` | string | имя роли через которую будет выпускаться сертификат | -| `.vault.certificate.CAPath ` | string | базовый путь PKI хранилища, где прописана роль | -| `.vault.certificate.rootCAPath` | string | базовый путь PKI root хранилища от кого будет выписываться intermediate | +| `.vault.resource` | object | инструция доступа к vault роли для выпуска сертификата | +| `.vault.resource.role` | string | имя роли через которую будет выпускаться сертификат | +| `.vault.resource.CAPath ` | string | базовый путь PKI хранилища, где прописана роль | +| `.vault.resource.rootCAPath` | string | базовый путь PKI root хранилища от кого будет выписываться intermediate | | `.vault.timeout ` | string | максимальное время ответа сервера Vault | +```yaml +--- +issuers: + - name: kubernetes-ca + vault: + server: http://example.com:9200 + auth: + caBundle: + tlsInsecure: true + bootstrap: + token: ${token} # <- или + path: /tmp/bootstrap-token # <- или + appRole: + name: kubernetes-ca + path: "clusters/cluster-1/approle" + secretIDLocalPath: /var/lib/key-keeper/vault/kubernetes-ca/secret-id + roleIDLocalPath: /var/lib/key-keeper/vault/kubernetes-ca/role-id + resource: + role: kubelet-server + CAPath: "clusters/cluster-1/pki/kubernetes" + rootCAPath: "clusters/cluster-1/pki/root" +``` + #### CERTIFICATES: | ключ | тип | описание | @@ -157,6 +119,42 @@ secrets: | `.updateBefore` | string | время до истечения сертификата - при достижении сертификат перевыпустится | | `.trigger` | list | список баш команд, которые выполнятся после обновления сертификата | +```yaml +certificates: + - name: kubernetes-ca + issuerRef: + name: kubernetes-ca + isCa: true + ca: + exportedKey: false + generate: false + hostPath: "/etc/kubernetes/pki/ca" + + - name: kubelet-server + issuerRef: + name: kubelet-server + spec: + subject: + commonName: "system:node:master-0.cluster-1.dobry-kot.ru" + usage: + - server auth + privateKey: + algorithm: "RSA" + encoding: "PKCS1" + size: 4096 + ipAddresses: + interfaces: + - lo + - eth* + ttl: 200h + hostnames: + - localhost + - "master-0.cluster-1.dobry-kot.ru" + renewBefore: 100h + hostPath: "/etc/kubernetes/pki/certs/kubelet" + +``` + #### SECRETS: | ключ | тип | описание | @@ -167,3 +165,14 @@ secrets: | `.issuerRef.name` | string | имя инструкции issuer | | `.key` | string | ключ в объекта секрета | | `.hostPath` | string | путь в локальной файловой системе, где будет сохранен секрет | + +```yaml +secrets: + - name: kube-apiserver-sa + issuerRef: + name: kube-apiserver-sa + key: public + kv: + path: clusters/cluster-1/kv + hostPath: /etc/kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pub +``` \ No newline at end of file From 6104d8a68177151f285468b7eb8dbe6d52a8576b Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Mon, 10 Oct 2022 17:15:39 +0300 Subject: [PATCH 192/220] =?UTF-8?q?=D0=A4=D0=B8=D0=BA=D1=81=20=D1=81=D1=82?= =?UTF-8?q?=D1=80=D1=83=D0=BA=D1=82=D1=83=D1=80=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b548635..3a3c00b 100644 --- a/README.md +++ b/README.md @@ -45,12 +45,12 @@ key-keeper -config-dir /path/to/config-dir -config-regexp .*.conf | `.vault.auth.appRole.path` | string | базовый путь approle в Vault | | `.vault.auth.appRole.roleIDLocalPath` | string | локальный путь, где будет искать role_id для авторизации | | `.vault.auth.appRole.secretIDLocalPath` | string | локальный путь, где будет искать secret_id для авторизации | -| `.vault.kv` | object | описание доступа в Vault к Key Value стореджу | -| `.vault.kv.path` | string | путь в Vault до Key Value стореджа | | `.vault.resource` | object | инструция доступа к vault роли для выпуска сертификата | | `.vault.resource.role` | string | имя роли через которую будет выпускаться сертификат | | `.vault.resource.CAPath ` | string | базовый путь PKI хранилища, где прописана роль | | `.vault.resource.rootCAPath` | string | базовый путь PKI root хранилища от кого будет выписываться intermediate | +| `.vault.resource.kv` | object | описание доступа в Vault к Key Value стореджу | +| `.vault.resource.kv.path` | string | путь в Vault до Key Value стореджа | | `.vault.timeout ` | string | максимальное время ответа сервера Vault | ```yaml @@ -74,6 +74,8 @@ issuers: role: kubelet-server CAPath: "clusters/cluster-1/pki/kubernetes" rootCAPath: "clusters/cluster-1/pki/root" + kv: + path: "clusters/cluster-1/kv" ``` #### CERTIFICATES: @@ -167,7 +169,5 @@ secrets: issuerRef: name: kube-apiserver-sa key: public - kv: - path: clusters/cluster-1/kv hostPath: /etc/kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pub ``` \ No newline at end of file From 76013e432efef490540b0d592f30d0616eaebbbf Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 10 Oct 2022 17:35:09 +0300 Subject: [PATCH 193/220] up --- internal/issuer/vault/certificate.go | 13 +++++---- internal/issuer/vault/vault.go | 40 ++++++++++++++++++---------- 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/internal/issuer/vault/certificate.go b/internal/issuer/vault/certificate.go index 26ddbd1..de4da09 100644 --- a/internal/issuer/vault/certificate.go +++ b/internal/issuer/vault/certificate.go @@ -2,7 +2,6 @@ package vault import ( "crypto/rand" - "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/pem" @@ -54,7 +53,7 @@ func (s *vault) checkCertificate(cert config.Certificate) { } func (s *vault) generateCertificate(certSpec config.Spec) ([]byte, []byte, error) { - csr, key, err := createCSR(certSpec) + csr, key, err := s.createCSR(certSpec) if err != nil { return nil, nil, fmt.Errorf("create csr: %w", err) } @@ -77,14 +76,14 @@ func (s *vault) generateCertificate(certSpec config.Spec) ([]byte, []byte, error return nil, nil, fmt.Errorf("certificate block not found") } -func createCSR(spec config.Spec) (crt, key []byte, err error) { - pk, err := rsa.GenerateKey(rand.Reader, spec.PrivateKey.Size) +func (s *vault) createCSR(spec config.Spec) (crt, key []byte, err error) { + pk, err := s.generateKey(spec.PrivateKey.Size) if err != nil { err = fmt.Errorf("generate key: %w", err) return } - ips, err := getIPAddresses(spec.IPAddresses) + ips, err := s.getIPAddresses(spec.IPAddresses) if err != nil { err = fmt.Errorf("get ip addresses: %w", err) return @@ -134,7 +133,7 @@ func createCSR(spec config.Spec) (crt, key []byte, err error) { return } -func getIPAddresses(cfg config.IPAddresses) ([]net.IP, error) { +func (s *vault) getIPAddresses(cfg config.IPAddresses) ([]net.IP, error) { ipAddresses := make(map[string]net.IP) for _, ip := range cfg.Static { @@ -144,7 +143,7 @@ func getIPAddresses(cfg config.IPAddresses) ([]net.IP, error) { } } - ifaces, err := net.Interfaces() + ifaces, err := s.getInterfaces() if err != nil { return nil, errors.New("get interfaces") } diff --git a/internal/issuer/vault/vault.go b/internal/issuer/vault/vault.go index 6aed08a..cafe6b6 100644 --- a/internal/issuer/vault/vault.go +++ b/internal/issuer/vault/vault.go @@ -1,6 +1,10 @@ package vault import ( + "crypto/rand" + "crypto/rsa" + "net" + "github.com/fraima/key-keeper/internal/config" "github.com/fraima/key-keeper/internal/controller" ) @@ -15,13 +19,15 @@ type Client interface { type vault struct { cli Client - name string - role string - caPath string - rootCAPath string - kv string - + name string + role string + caPath string + rootCAPath string + kv string certificate map[string]config.Certificate + + generateKey func(size int) (*rsa.PrivateKey, error) + getInterfaces func() ([]net.Interface, error) } func Connector( @@ -33,17 +39,23 @@ func Connector( return nil, err } - return &vault{ + v := &vault{ cli: driver, - name: cfg.Name, - role: cfg.Vault.Resource.Role, - caPath: cfg.Vault.Resource.CAPath, - rootCAPath: cfg.Vault.Resource.RootCAPath, - kv: cfg.Vault.Resource.KV.Path, - + name: cfg.Name, + role: cfg.Vault.Resource.Role, + caPath: cfg.Vault.Resource.CAPath, + rootCAPath: cfg.Vault.Resource.RootCAPath, + kv: cfg.Vault.Resource.KV.Path, certificate: make(map[string]config.Certificate), - }, nil + } + + v.generateKey = func(size int) (*rsa.PrivateKey, error) { + return rsa.GenerateKey(rand.Reader, size) + } + v.getInterfaces = net.Interfaces + + return v, nil } } From 0bd50f08a307292c760c650b5064a334cbf32d42 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 10 Oct 2022 19:53:11 +0300 Subject: [PATCH 194/220] up --- internal/issuer/vault/ca-certificate.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/issuer/vault/ca-certificate.go b/internal/issuer/vault/ca-certificate.go index 8291eb7..550caf3 100644 --- a/internal/issuer/vault/ca-certificate.go +++ b/internal/issuer/vault/ca-certificate.go @@ -32,7 +32,7 @@ func (s *vault) checkCA(cert config.Certificate) { ca, err = parseCertificate(crt) if err == nil { logger.Debug("ttl", zap.Float64("remaining time(h)", time.Until(ca.NotAfter).Hours())) - if time.Until(ca.NotAfter) < cert.UpdateBefore { + if time.Until(ca.NotAfter) <= cert.UpdateBefore { err = fmt.Errorf("expired until(h) %f", time.Until(ca.NotAfter).Hours()) } } From e667fdd9f2f76f536b3b10c1a5ba8af4a1a09c4e Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Mon, 10 Oct 2022 19:54:37 +0300 Subject: [PATCH 195/220] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D0=B5=D1=82=20=D0=B4=D0=BE=D0=BF=20=D0=BE=D0=BF=D0=B8?= =?UTF-8?q?=D1=81=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=BA=20=D0=BF=D1=80=D0=B8?= =?UTF-8?q?=D0=BC=D0=B5=D1=80=D0=B0=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3a3c00b..1a545b7 100644 --- a/README.md +++ b/README.md @@ -132,7 +132,7 @@ certificates: name: kubelet-server spec: subject: - commonName: "system:node:master-0.cluster-1.dobry-kot.ru" + commonName: "system:node:master-0.cluster-1.example.com" usage: - server auth privateKey: @@ -140,13 +140,24 @@ certificates: encoding: "PKCS1" size: 4096 ipAddresses: + static: + - 1.1.1.1 + ### + # * -> Позволяет указывать регексп интерфейсов (на выходе получаем список) interfaces: - lo - eth* + ### + # * -> В цикле будет пытаться отрезолвить имя, без выходного значения, сертификат не будет заказан. + dnsLookup: + - api.example.com ttl: 200h + ### + # * -> Указав $HOSTNAME - hostname хоста добавится в поле AltNames сертификата. hostnames: + - $HOSTNAME - localhost - - "master-0.cluster-1.dobry-kot.ru" + - "master-0.cluster-1.example.com" renewBefore: 100h hostPath: "/etc/kubernetes/pki/certs/kubelet" From 5b90f50d8f0a41e5d7d53edce4a8b456199204db Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 18 Oct 2022 16:44:58 +0300 Subject: [PATCH 196/220] ref --- go.mod | 3 + internal/controller/controller.go | 11 ++- internal/issuer/vault/ca-certificate.go | 57 +++++++------ internal/issuer/vault/certificate.go | 28 +++--- internal/issuer/vault/secret.go | 2 +- internal/issuer/vault/vault.go | 22 ++--- internal/mocks/vault-client.go | 108 ++++++++++++++++++++++++ 7 files changed, 168 insertions(+), 63 deletions(-) create mode 100644 internal/mocks/vault-client.go diff --git a/go.mod b/go.mod index 50a07f0..9f77880 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.19 require ( github.com/hashicorp/vault/api v1.7.1 github.com/hashicorp/vault/api/auth/approle v0.1.1 + github.com/stretchr/testify v1.7.0 go.uber.org/zap v1.21.0 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b ) @@ -13,6 +14,7 @@ require ( github.com/armon/go-metrics v0.3.9 // indirect github.com/armon/go-radix v1.0.0 // indirect github.com/cenkalti/backoff/v3 v3.0.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/fatih/color v1.7.0 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.4 // indirect @@ -43,6 +45,7 @@ require ( github.com/mitchellh/reflectwalk v1.0.0 // indirect github.com/oklog/run v1.0.0 // indirect github.com/pierrec/lz4 v2.5.2+incompatible // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect github.com/stretchr/objx v0.2.0 // indirect go.uber.org/atomic v1.9.0 // indirect diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 14c49e6..16f7267 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -13,7 +13,7 @@ import ( type Issuer interface { Name() string AddResource(config.Resources) - CheckResource() + EnsureResource() } type controller struct { @@ -49,15 +49,14 @@ func (s *controller) Start() error { } }() - // start resource checking + // start resource ensure go func() { for range time.NewTicker(30 * time.Second).C { - s.issuer.Range(func(key, value any) bool { issuer := value.(Issuer) - zap.L().Debug("start_checking", zap.String("issuer", issuer.Name())) - issuer.CheckResource() - zap.L().Debug("finish_checking", zap.String("issuer", issuer.Name())) + zap.L().Debug("start_ensure", zap.String("issuer", issuer.Name())) + issuer.EnsureResource() + zap.L().Debug("finish_ensure", zap.String("issuer", issuer.Name())) return true }) } diff --git a/internal/issuer/vault/ca-certificate.go b/internal/issuer/vault/ca-certificate.go index 550caf3..3daec03 100644 --- a/internal/issuer/vault/ca-certificate.go +++ b/internal/issuer/vault/ca-certificate.go @@ -11,7 +11,7 @@ import ( "github.com/fraima/key-keeper/internal/config" ) -func (s *vault) checkCA(cert config.Certificate) { +func (s *vault) ensureCA(cert config.Certificate) { logger := zap.L().With(zap.String("resource_type", "intermediate_ca"), zap.String("name", cert.Name)) var ( @@ -26,18 +26,7 @@ func (s *vault) checkCA(cert config.Certificate) { logger.Debug("store") }() - crt, key, err = s.readCA(s.caPath) - if err == nil { - var ca *x509.Certificate - ca, err = parseCertificate(crt) - if err == nil { - logger.Debug("ttl", zap.Float64("remaining time(h)", time.Until(ca.NotAfter).Hours())) - if time.Until(ca.NotAfter) <= cert.UpdateBefore { - err = fmt.Errorf("expired until(h) %f", time.Until(ca.NotAfter).Hours()) - } - } - } - + crt, key, err = s.checkCA(cert, logger) if err == nil { return } @@ -53,6 +42,34 @@ func (s *vault) checkCA(cert config.Certificate) { } } +func (s *vault) checkCA(cert config.Certificate, l *zap.Logger) ([]byte, []byte, error) { + crt, key, err := s.readCA(s.caPath) + if err == nil { + var ca *x509.Certificate + ca, err = parseCertificate(crt) + if err == nil { + if time.Until(ca.NotAfter) <= cert.UpdateBefore { + err = fmt.Errorf("expired until(h) %f", time.Until(ca.NotAfter).Hours()) + } + } + } + return crt, key, err +} + +func (s *vault) readCA(vaultPath string) (crt, key []byte, err error) { + vaultPath = path.Join(vaultPath, "cert/ca_chain") + ica, err := s.cli.Read(vaultPath) + if ica != nil { + if c, ok := ica["certificate"]; ok { + crt = []byte(c.(string)) + } + if k, ok := ica["private_key"]; ok { + key = []byte(k.(string)) + } + } + return +} + func (s *vault) generateCA(cert config.Certificate) (crt, key []byte, err error) { csrData := map[string]interface{}{ "common_name": fmt.Sprintf("%s Intermediate Authority", cert.Name), @@ -102,17 +119,3 @@ func (s *vault) generateCA(cert config.Certificate) (crt, key []byte, err error) } return } - -func (s *vault) readCA(vaultPath string) (crt, key []byte, err error) { - vaultPath = path.Join(vaultPath, "cert/ca_chain") - ica, err := s.cli.Read(vaultPath) - if ica != nil { - if c, ok := ica["certificate"]; ok { - crt = []byte(c.(string)) - } - if k, ok := ica["private_key"]; ok { - key = []byte(k.(string)) - } - } - return -} diff --git a/internal/issuer/vault/certificate.go b/internal/issuer/vault/certificate.go index de4da09..3e9531c 100644 --- a/internal/issuer/vault/certificate.go +++ b/internal/issuer/vault/certificate.go @@ -2,6 +2,7 @@ package vault import ( "crypto/rand" + "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/pem" @@ -19,21 +20,14 @@ import ( "github.com/fraima/key-keeper/internal/config" ) -func (s *vault) checkCertificate(cert config.Certificate) { +func (s *vault) ensureCertificate(cert config.Certificate) { logger := zap.L().With(zap.String("resource_type", "certificate"), zap.String("name", cert.Name)) - crt, err := readCertificate(cert.HostPath, cert.Name) - if crt != nil { - logger.Debug("ttl", zap.Float64("remaining time(h)", time.Until(crt.NotAfter).Hours())) - if time.Until(crt.NotAfter) <= cert.UpdateBefore { - err = fmt.Errorf("expired until(h) %f", time.Until(crt.NotAfter).Hours()) - } - } - + err := checkCertificate(cert, logger) if err == nil { return } - zap.L().Warn("check", zap.Error(err)) + zap.L().Warn("ensure", zap.Error(err)) if os.IsNotExist(err) || cert.WithUpdate { crt, key, err := s.generateCertificate(cert.Spec) @@ -77,7 +71,7 @@ func (s *vault) generateCertificate(certSpec config.Spec) ([]byte, []byte, error } func (s *vault) createCSR(spec config.Spec) (crt, key []byte, err error) { - pk, err := s.generateKey(spec.PrivateKey.Size) + pk, err := rsa.GenerateKey(rand.Reader, spec.PrivateKey.Size) if err != nil { err = fmt.Errorf("generate key: %w", err) return @@ -143,7 +137,7 @@ func (s *vault) getIPAddresses(cfg config.IPAddresses) ([]net.IP, error) { } } - ifaces, err := s.getInterfaces() + ifaces, err := net.Interfaces() if err != nil { return nil, errors.New("get interfaces") } @@ -210,6 +204,16 @@ func inSlice(str string, sl []string) bool { return false } +func checkCertificate(cert config.Certificate, l *zap.Logger) error { + crt, err := readCertificate(cert.HostPath, cert.Name) + if crt != nil { + if time.Until(crt.NotAfter) <= cert.UpdateBefore { + err = fmt.Errorf("expired until(h) %f", time.Until(crt.NotAfter).Hours()) + } + } + return err +} + func trigger(trigger [][]string, logger *zap.Logger) { for _, command := range trigger { var err error diff --git a/internal/issuer/vault/secret.go b/internal/issuer/vault/secret.go index 93bb189..e6d7c97 100644 --- a/internal/issuer/vault/secret.go +++ b/internal/issuer/vault/secret.go @@ -8,7 +8,7 @@ import ( "github.com/fraima/key-keeper/internal/config" ) -func (s *vault) checkSecret(i config.Secret) { +func (s *vault) ensureSecret(i config.Secret) { logger := zap.L().With(zap.String("resource_type", "secret"), zap.String("name", i.Name)) secret, err := s.readSecret(i) diff --git a/internal/issuer/vault/vault.go b/internal/issuer/vault/vault.go index cafe6b6..2a4a06f 100644 --- a/internal/issuer/vault/vault.go +++ b/internal/issuer/vault/vault.go @@ -1,10 +1,6 @@ package vault import ( - "crypto/rand" - "crypto/rsa" - "net" - "github.com/fraima/key-keeper/internal/config" "github.com/fraima/key-keeper/internal/controller" ) @@ -25,9 +21,6 @@ type vault struct { rootCAPath string kv string certificate map[string]config.Certificate - - generateKey func(size int) (*rsa.PrivateKey, error) - getInterfaces func() ([]net.Interface, error) } func Connector( @@ -50,11 +43,6 @@ func Connector( certificate: make(map[string]config.Certificate), } - v.generateKey = func(size int) (*rsa.PrivateKey, error) { - return rsa.GenerateKey(rand.Reader, size) - } - v.getInterfaces = net.Interfaces - return v, nil } } @@ -69,20 +57,20 @@ func (s *vault) AddResource(r config.Resources) { } for _, secret := range r.Secrets { go func(secret config.Secret) { - s.checkSecret(secret) + s.ensureSecret(secret) }(secret) } - s.CheckResource() + s.EnsureResource() } -func (s *vault) CheckResource() { +func (s *vault) EnsureResource() { for _, cert := range s.certificate { go func(c config.Certificate) { if c.IsCA { - s.checkCA(c) + s.ensureCA(c) return } - s.checkCertificate(c) + s.ensureCertificate(c) }(cert) } } diff --git a/internal/mocks/vault-client.go b/internal/mocks/vault-client.go new file mode 100644 index 0000000..a8b7d4f --- /dev/null +++ b/internal/mocks/vault-client.go @@ -0,0 +1,108 @@ +// Code generated by mockery v2.13.1. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// Client is an autogenerated mock type for the Client type +type Client struct { + mock.Mock +} + +// Get provides a mock function with given fields: kvMountPath, secretePath +func (_m *Client) Get(kvMountPath string, secretePath string) (map[string]interface{}, error) { + ret := _m.Called(kvMountPath, secretePath) + + var r0 map[string]interface{} + if rf, ok := ret.Get(0).(func(string, string) map[string]interface{}); ok { + r0 = rf(kvMountPath, secretePath) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[string]interface{}) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string, string) error); ok { + r1 = rf(kvMountPath, secretePath) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Put provides a mock function with given fields: kvMountPath, secretePath, data +func (_m *Client) Put(kvMountPath string, secretePath string, data map[string]interface{}) error { + ret := _m.Called(kvMountPath, secretePath, data) + + var r0 error + if rf, ok := ret.Get(0).(func(string, string, map[string]interface{}) error); ok { + r0 = rf(kvMountPath, secretePath, data) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Read provides a mock function with given fields: path +func (_m *Client) Read(path string) (map[string]interface{}, error) { + ret := _m.Called(path) + + var r0 map[string]interface{} + if rf, ok := ret.Get(0).(func(string) map[string]interface{}); ok { + r0 = rf(path) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[string]interface{}) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(path) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Write provides a mock function with given fields: path, data +func (_m *Client) Write(path string, data map[string]interface{}) (map[string]interface{}, error) { + ret := _m.Called(path, data) + + var r0 map[string]interface{} + if rf, ok := ret.Get(0).(func(string, map[string]interface{}) map[string]interface{}); ok { + r0 = rf(path, data) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[string]interface{}) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string, map[string]interface{}) error); ok { + r1 = rf(path, data) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +type mockConstructorTestingTNewClient interface { + mock.TestingT + Cleanup(func()) +} + +// NewClient creates a new instance of Client. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewClient(t mockConstructorTestingTNewClient) *Client { + mock := &Client{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} From 7546bbe8bf7650dbd75a74d15a310a507aba2b04 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 20 Oct 2022 15:14:31 +0300 Subject: [PATCH 197/220] fix --- internal/config/types.go | 18 +++++++++--------- internal/controller/error.go | 2 +- internal/issuer/vault/ca-certificate.go | 2 +- internal/issuer/vault/certificate.go | 2 +- internal/issuer/vault/client/auth.go | 6 +++--- internal/issuer/vault/utils.go | 6 +++--- internal/issuer/vault/vault.go | 4 +--- 7 files changed, 19 insertions(+), 21 deletions(-) diff --git a/internal/config/types.go b/internal/config/types.go index 6f44352..c41a354 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -18,15 +18,15 @@ type Resources struct { } type Certificate struct { - Name string `yaml:"name"` - IssuerRef IssuerRef `yaml:"issuerRef"` - IsCA bool `yaml:"isCa"` - CA CA `yaml:"ca"` - Spec Spec `yaml:"spec"` - HostPath string `yaml:"hostPath"` - WithUpdate bool `yaml:"withUpdate"` - UpdateBefore time.Duration `yaml:"updateBefore"` - Trigger [][]string `yaml:"trigger"` + Name string `yaml:"name"` + IssuerRef IssuerRef `yaml:"issuerRef"` + IsCA bool `yaml:"isCa"` + CA CA `yaml:"ca"` + Spec Spec `yaml:"spec"` + HostPath string `yaml:"hostPath"` + WithUpdate bool `yaml:"withUpdate"` + RenewBefore time.Duration `yaml:"renewBefore"` + Trigger [][]string `yaml:"trigger"` } type Secret struct { diff --git a/internal/controller/error.go b/internal/controller/error.go index 3caa61f..4407ce5 100644 --- a/internal/controller/error.go +++ b/internal/controller/error.go @@ -4,5 +4,5 @@ import "errors" var ( errIssuerIsExist = errors.New("issuer is exist") - errIssuerIsNotExist = errors.New("issuer is notexist") + errIssuerIsNotExist = errors.New("issuer is not exist") ) diff --git a/internal/issuer/vault/ca-certificate.go b/internal/issuer/vault/ca-certificate.go index 3daec03..f0d6cd6 100644 --- a/internal/issuer/vault/ca-certificate.go +++ b/internal/issuer/vault/ca-certificate.go @@ -48,7 +48,7 @@ func (s *vault) checkCA(cert config.Certificate, l *zap.Logger) ([]byte, []byte, var ca *x509.Certificate ca, err = parseCertificate(crt) if err == nil { - if time.Until(ca.NotAfter) <= cert.UpdateBefore { + if time.Until(ca.NotAfter) <= cert.RenewBefore { err = fmt.Errorf("expired until(h) %f", time.Until(ca.NotAfter).Hours()) } } diff --git a/internal/issuer/vault/certificate.go b/internal/issuer/vault/certificate.go index 3e9531c..9597c32 100644 --- a/internal/issuer/vault/certificate.go +++ b/internal/issuer/vault/certificate.go @@ -207,7 +207,7 @@ func inSlice(str string, sl []string) bool { func checkCertificate(cert config.Certificate, l *zap.Logger) error { crt, err := readCertificate(cert.HostPath, cert.Name) if crt != nil { - if time.Until(crt.NotAfter) <= cert.UpdateBefore { + if time.Until(crt.NotAfter) <= cert.RenewBefore { err = fmt.Errorf("expired until(h) %f", time.Until(crt.NotAfter).Hours()) } } diff --git a/internal/issuer/vault/client/auth.go b/internal/issuer/vault/client/auth.go index 45767eb..2bff331 100644 --- a/internal/issuer/vault/client/auth.go +++ b/internal/issuer/vault/client/auth.go @@ -63,7 +63,7 @@ func (s *client) roleID(name string, appRole config.AppRole) (string, error) { return "", fmt.Errorf("read role_id for path: %s : %w", vaultPath, err) } if role == nil { - return "", fmt.Errorf("no role_id info was returned") + return "", fmt.Errorf("role_id info was not returned") } roleID, ok := role["role_id"] @@ -88,7 +88,7 @@ func (s *client) secretID(name string, appRole config.AppRole) (string, error) { return "", fmt.Errorf("read secrete_id for path: %s : %w", vaultPath, err) } if secret == nil { - return "", fmt.Errorf("no secrete_id info was returned") + return "", fmt.Errorf("secrete_id info was not returned") } secretID, ok := secret["secret_id"] @@ -108,7 +108,7 @@ func (s *client) updateAuthToken(appRoleAuth *auth.AppRoleAuth) (time.Duration, return 0, err } if authInfo == nil { - return 0, fmt.Errorf("no auth info was returned after login") + return 0, fmt.Errorf("auth info was not returned after login") } token, err := authInfo.TokenID() diff --git a/internal/issuer/vault/utils.go b/internal/issuer/vault/utils.go index 28a4695..b756af4 100644 --- a/internal/issuer/vault/utils.go +++ b/internal/issuer/vault/utils.go @@ -10,7 +10,7 @@ import ( ) func storeKeyPair(filepath string, name string, crt, key []byte) error { - if err := os.MkdirAll(filepath, 0644); err != nil { + if err := os.MkdirAll(filepath, 0777); err != nil { return fmt.Errorf("mkdir all %s : %w", filepath, err) } @@ -19,7 +19,7 @@ func storeKeyPair(filepath string, name string, crt, key []byte) error { data, err := os.ReadFile(crtPath) if err != nil || !reflect.DeepEqual(crt, data) { if err := os.WriteFile(crtPath, crt, 0644); err != nil { - return fmt.Errorf("failed to save certificate with path: %w", err) + return fmt.Errorf("failed to save certificate: %w", err) } } } @@ -52,7 +52,7 @@ func parseCertificate(crt []byte) (*x509.Certificate, error) { func writeToFile(filepath string, date []byte) error { dir := path.Dir(filepath) - if err := os.MkdirAll(dir, os.ModePerm); err != nil { + if err := os.MkdirAll(dir, 0777); err != nil { return err } return os.WriteFile(filepath, date, 0644) diff --git a/internal/issuer/vault/vault.go b/internal/issuer/vault/vault.go index 2a4a06f..00e68af 100644 --- a/internal/issuer/vault/vault.go +++ b/internal/issuer/vault/vault.go @@ -33,8 +33,7 @@ func Connector( } v := &vault{ - cli: driver, - + cli: driver, name: cfg.Name, role: cfg.Vault.Resource.Role, caPath: cfg.Vault.Resource.CAPath, @@ -42,7 +41,6 @@ func Connector( kv: cfg.Vault.Resource.KV.Path, certificate: make(map[string]config.Certificate), } - return v, nil } } From 9b9ae88c9dd08ee29933c93cee6a8fb3e2849977 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 20 Oct 2022 17:38:46 +0300 Subject: [PATCH 198/220] up --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1a545b7..a8727ec 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ make build-and-push DOCKER_USER=geoirb ``` -# Build bin +## Build bin ```bash go build -o key-keeper cmd/key-keeper/main.go From 27be494514a03482a4b8460e157af0cccdbd057f Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 24 Oct 2022 11:36:58 +0300 Subject: [PATCH 199/220] formatting --- Makefile | 1 + internal/issuer/vault/client/client.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 25febd2..45abb5c 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,7 @@ build-and-push: docker image push $(tag) formatting: + go fmt ./... go install github.com/daixiang0/gci@latest gci write --skip-generated -s standard -s default -s "prefix(github.com/fraima/key-keeper)" . diff --git a/internal/issuer/vault/client/client.go b/internal/issuer/vault/client/client.go index 209c19e..20fb9b8 100644 --- a/internal/issuer/vault/client/client.go +++ b/internal/issuer/vault/client/client.go @@ -24,7 +24,7 @@ func Connect(name string, cfg config.Vault) (vault.Client, error) { &api.Config{ Address: cfg.Server, HttpClient: &http.Client{ - Timeout: 10 *time.Second, + Timeout: 10 * time.Second, }, }, ) From 992ccfda3a748ce87f2e5c2993089606654661f2 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Mon, 24 Oct 2022 17:43:01 +0300 Subject: [PATCH 200/220] fix nil crt --- internal/issuer/vault/ca-certificate.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/issuer/vault/ca-certificate.go b/internal/issuer/vault/ca-certificate.go index f0d6cd6..72d70a5 100644 --- a/internal/issuer/vault/ca-certificate.go +++ b/internal/issuer/vault/ca-certificate.go @@ -44,6 +44,9 @@ func (s *vault) ensureCA(cert config.Certificate) { func (s *vault) checkCA(cert config.Certificate, l *zap.Logger) ([]byte, []byte, error) { crt, key, err := s.readCA(s.caPath) + if crt == nil || key == nil { + return nil, nil, fmt.Errorf("crt or key is empty path: %s", s.caPath) + } if err == nil { var ca *x509.Certificate ca, err = parseCertificate(crt) From befddcf46f263e0af4fb73e901830a77abcb6dca Mon Sep 17 00:00:00 2001 From: irbgeo Date: Wed, 9 Nov 2022 16:25:13 +0300 Subject: [PATCH 201/220] work with token --- internal/issuer/vault/client/auth.go | 54 ++++++++++++++++++++------ internal/issuer/vault/client/client.go | 25 ++++-------- 2 files changed, 51 insertions(+), 28 deletions(-) diff --git a/internal/issuer/vault/client/auth.go b/internal/issuer/vault/client/auth.go index 2bff331..3214536 100644 --- a/internal/issuer/vault/client/auth.go +++ b/internal/issuer/vault/client/auth.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "path" + "strings" "time" auth "github.com/hashicorp/vault/api/auth/approle" @@ -34,18 +35,20 @@ func (s *client) auth(name string, a config.Auth) error { return err } - ttl, err := s.updateAuthToken(appRoleAuth) + token, ttl, err := s.getRoleToken(appRoleAuth) if err != nil { return err } + s.cli.SetToken(token) go func() { t := time.NewTimer(ttl / 2) for range t.C { - ttl, err := s.updateAuthToken(appRoleAuth) + token, ttl, err := s.getRoleToken(appRoleAuth) if err != nil { zap.L().Error("update auth token", zap.String("issuer_name", name), zap.Error(err)) } + s.cli.SetToken(token) t.Reset(ttl / 2) } }() @@ -53,7 +56,7 @@ func (s *client) auth(name string, a config.Auth) error { } func (s *client) roleID(name string, appRole config.AppRole) (string, error) { - if roleID, rErr := os.ReadFile(appRole.RoleIDLocalPath); rErr == nil { + if roleID, err := os.ReadFile(appRole.RoleIDLocalPath); err == nil { return string(roleID), nil } @@ -78,7 +81,7 @@ func (s *client) roleID(name string, appRole config.AppRole) (string, error) { } func (s *client) secretID(name string, appRole config.AppRole) (string, error) { - if secretID, rErr := os.ReadFile(appRole.SecretIDLocalPath); rErr == nil { + if secretID, err := os.ReadFile(appRole.SecretIDLocalPath); err == nil { return string(secretID), nil } @@ -102,24 +105,53 @@ func (s *client) secretID(name string, appRole config.AppRole) (string, error) { return secretID.(string), err } -func (s *client) updateAuthToken(appRoleAuth *auth.AppRoleAuth) (time.Duration, error) { +func (s *client) getRoleToken(appRoleAuth *auth.AppRoleAuth) (string, time.Duration, error) { authInfo, err := s.cli.Auth().Login(context.Background(), appRoleAuth) if err != nil { - return 0, err + return "", 0, err } if authInfo == nil { - return 0, fmt.Errorf("auth info was not returned after login") + return "", 0, fmt.Errorf("auth info was not returned after login") } token, err := authInfo.TokenID() if err != nil { - return 0, err + return "", 0, err } - s.cli.SetToken(token) ttl, err := authInfo.TokenTTL() if err != nil { - return 0, err + return "", 0, err } - return ttl, nil + return token, ttl, nil +} + +func (s *client) getToken(a config.Auth) (string, error) { + secretID, sErr := os.ReadFile(a.AppRole.SecretIDLocalPath) + roleID, rErr := os.ReadFile(a.AppRole.RoleIDLocalPath) + + if sErr == nil && rErr == nil { + appRoleAuth, err := auth.NewAppRoleAuth( + string(roleID), + &auth.SecretID{ + FromString: string(secretID), + }, + auth.WithMountPath(a.AppRole.Path), + ) + if err != nil { + + } + token, _, err := s.getRoleToken(appRoleAuth) + if err != nil { + + } + return token, nil + } + + if a.Bootstrap.Token != "" { + return a.Bootstrap.Token, nil + } + + data, err := os.ReadFile(a.Bootstrap.File) + return strings.TrimSuffix(string(data), "\n"), err } diff --git a/internal/issuer/vault/client/client.go b/internal/issuer/vault/client/client.go index 20fb9b8..462bac5 100644 --- a/internal/issuer/vault/client/client.go +++ b/internal/issuer/vault/client/client.go @@ -4,8 +4,6 @@ import ( "context" "fmt" "net/http" - "os" - "strings" "time" "github.com/hashicorp/vault/api" @@ -32,12 +30,6 @@ func Connect(name string, cfg config.Vault) (vault.Client, error) { return nil, fmt.Errorf("new vault client: %w", err) } - token, err := getToken(cfg.Auth.Bootstrap) - if err != nil { - return nil, fmt.Errorf("get vault token: %w", err) - } - - cli.SetToken(token) if !cfg.Auth.TLSInsecure { err = cli.CloneConfig().ConfigureTLS(&api.TLSConfig{CACert: cfg.Auth.CABundle}) if err != nil { @@ -48,6 +40,14 @@ func Connect(name string, cfg config.Vault) (vault.Client, error) { s := &client{ cli: cli, } + + token, err := s.getToken(cfg.Auth) + if err != nil { + return nil, fmt.Errorf("get vault token: %w", err) + } + + s.cli.SetToken(token) + return s, s.auth(name, cfg.Auth) } @@ -83,12 +83,3 @@ func (s *client) Get(kvMountPath, secretePath string) (map[string]interface{}, e } return nil, err } - -func getToken(b config.Bootstrap) (string, error) { - if b.Token != "" { - return b.Token, nil - } - - data, err := os.ReadFile(b.File) - return strings.TrimSuffix(string(data), "\n"), err -} From cf0c4a4e31b0a6ccbf163319ffde626528aecb2d Mon Sep 17 00:00:00 2001 From: irbgeo Date: Wed, 9 Nov 2022 16:52:56 +0300 Subject: [PATCH 202/220] return --- internal/issuer/vault/client/auth.go | 53 +++++++++----------------- internal/issuer/vault/client/client.go | 10 ++--- 2 files changed, 22 insertions(+), 41 deletions(-) diff --git a/internal/issuer/vault/client/auth.go b/internal/issuer/vault/client/auth.go index 3214536..f55762e 100644 --- a/internal/issuer/vault/client/auth.go +++ b/internal/issuer/vault/client/auth.go @@ -15,11 +15,17 @@ import ( ) func (s *client) auth(name string, a config.Auth) error { - roleID, err := s.roleID(name, a.AppRole) + token, err := s.getBootstrapToken(a.Bootstrap) + if err != nil { + return fmt.Errorf("get vault token: %w", err) + } + s.cli.SetToken(token) + + roleID, err := s.getRoleID(name, a.AppRole) if err != nil { return fmt.Errorf("get role id: %w", err) } - secretID, err := s.secretID(name, a.AppRole) + secretID, err := s.getSecretID(name, a.AppRole) if err != nil { return fmt.Errorf("get secret id: %w", err) } @@ -55,7 +61,16 @@ func (s *client) auth(name string, a config.Auth) error { return nil } -func (s *client) roleID(name string, appRole config.AppRole) (string, error) { +func (s *client) getBootstrapToken(a config.Bootstrap) (string, error) { + if a.Token != "" { + return a.Token, nil + } + + data, err := os.ReadFile(a.File) + return strings.TrimSuffix(string(data), "\n"), err +} + +func (s *client) getRoleID(name string, appRole config.AppRole) (string, error) { if roleID, err := os.ReadFile(appRole.RoleIDLocalPath); err == nil { return string(roleID), nil } @@ -80,7 +95,7 @@ func (s *client) roleID(name string, appRole config.AppRole) (string, error) { return roleID.(string), err } -func (s *client) secretID(name string, appRole config.AppRole) (string, error) { +func (s *client) getSecretID(name string, appRole config.AppRole) (string, error) { if secretID, err := os.ReadFile(appRole.SecretIDLocalPath); err == nil { return string(secretID), nil } @@ -125,33 +140,3 @@ func (s *client) getRoleToken(appRoleAuth *auth.AppRoleAuth) (string, time.Durat } return token, ttl, nil } - -func (s *client) getToken(a config.Auth) (string, error) { - secretID, sErr := os.ReadFile(a.AppRole.SecretIDLocalPath) - roleID, rErr := os.ReadFile(a.AppRole.RoleIDLocalPath) - - if sErr == nil && rErr == nil { - appRoleAuth, err := auth.NewAppRoleAuth( - string(roleID), - &auth.SecretID{ - FromString: string(secretID), - }, - auth.WithMountPath(a.AppRole.Path), - ) - if err != nil { - - } - token, _, err := s.getRoleToken(appRoleAuth) - if err != nil { - - } - return token, nil - } - - if a.Bootstrap.Token != "" { - return a.Bootstrap.Token, nil - } - - data, err := os.ReadFile(a.Bootstrap.File) - return strings.TrimSuffix(string(data), "\n"), err -} diff --git a/internal/issuer/vault/client/client.go b/internal/issuer/vault/client/client.go index 462bac5..146238e 100644 --- a/internal/issuer/vault/client/client.go +++ b/internal/issuer/vault/client/client.go @@ -41,14 +41,10 @@ func Connect(name string, cfg config.Vault) (vault.Client, error) { cli: cli, } - token, err := s.getToken(cfg.Auth) - if err != nil { - return nil, fmt.Errorf("get vault token: %w", err) + if err = s.auth(name, cfg.Auth); err != nil { + return nil, fmt.Errorf("auth: %w", err) } - - s.cli.SetToken(token) - - return s, s.auth(name, cfg.Auth) + return s, err } // Read secret from vault by path. From 987a5f48da241e93491b792fee23c07b1ca2fda1 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Wed, 9 Nov 2022 16:59:20 +0300 Subject: [PATCH 203/220] refactoring --- internal/issuer/vault/client/auth.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/issuer/vault/client/auth.go b/internal/issuer/vault/client/auth.go index f55762e..fd5cb8d 100644 --- a/internal/issuer/vault/client/auth.go +++ b/internal/issuer/vault/client/auth.go @@ -38,12 +38,12 @@ func (s *client) auth(name string, a config.Auth) error { auth.WithMountPath(a.AppRole.Path), ) if err != nil { - return err + return fmt.Errorf("app role auth: %w", err) } token, ttl, err := s.getRoleToken(appRoleAuth) if err != nil { - return err + return fmt.Errorf("get role token: %w", err) } s.cli.SetToken(token) From bb55447953c19f82779ccf42620ffda8e7863d98 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 24 Nov 2022 13:42:32 +0300 Subject: [PATCH 204/220] up readme --- README.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index a8727ec..924a447 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -### key-keeper +# key-keeper инструмент для linux хостов, позволяющий заказывать в Vault хранилище сертификаты и секреты и следить за их актуальностью. @@ -63,8 +63,8 @@ issuers: caBundle: tlsInsecure: true bootstrap: - token: ${token} # <- или - path: /tmp/bootstrap-token # <- или + token: ${token} # <- или + path: /tmp/bootstrap-token # <- или appRole: name: kubernetes-ca path: "clusters/cluster-1/approle" @@ -74,7 +74,7 @@ issuers: role: kubelet-server CAPath: "clusters/cluster-1/pki/kubernetes" rootCAPath: "clusters/cluster-1/pki/root" - kv: + kv: path: "clusters/cluster-1/kv" ``` @@ -150,7 +150,7 @@ certificates: ### # * -> В цикле будет пытаться отрезолвить имя, без выходного значения, сертификат не будет заказан. dnsLookup: - - api.example.com + - api.example.com ttl: 200h ### # * -> Указав $HOSTNAME - hostname хоста добавится в поле AltNames сертификата. @@ -160,7 +160,6 @@ certificates: - "master-0.cluster-1.example.com" renewBefore: 100h hostPath: "/etc/kubernetes/pki/certs/kubelet" - ``` #### SECRETS: @@ -181,4 +180,4 @@ secrets: name: kube-apiserver-sa key: public hostPath: /etc/kubernetes/pki/certs/kube-apiserver/kube-apiserver-sa.pub -``` \ No newline at end of file +``` From 7b5b354affd6cf9467511422181e1e7f811366c2 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 29 Nov 2022 17:06:27 +0300 Subject: [PATCH 205/220] up Makefile | up Dockerfile --- Dockerfile | 7 ++++--- Makefile | 13 ++++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index d2c218a..9622221 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,13 +8,14 @@ RUN go mod download COPY . . ARG VERSION +ARG PROJECT RUN go install -ldflags "-s \ -X main.Version=${VERSION}" \ - /app/cmd/key-keeper + /app/cmd/${PROJECT} FROM alpine:3.15.0 -COPY --from=builder /go/bin/key-keeper /usr/local/bin/key-keeper +COPY --from=builder /go/bin/${PROJECT} /usr/local/bin/${PROJECT} -ENTRYPOINT ["/usr/local/bin/key-keeper"] \ No newline at end of file +ENTRYPOINT [${PROJECT}] \ No newline at end of file diff --git a/Makefile b/Makefile index 45abb5c..7c4264a 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,18 @@ -release = $(shell cat .release) -tag = $(DOCKER_USER)/key-keeper:$(release) +project = key-keeper#change for new project +release = v1.0.0 + +tag = $(DOCKER_USER)/$(project):$(release) pwd = $(shell pwd) +module = $(shell head -n 1 1 go.mod| awk '{print $2}') build-and-push: - docker build -t $(tag) --build-arg VERSION=$(release) -f Dockerfile . - docker image push $(tag) + docker build -t $(tag) --build-arg VERSION=$(release) --build-arg PROJECT=$(project) -f Dockerfile . + # docker image push $(tag) formatting: go fmt ./... go install github.com/daixiang0/gci@latest - gci write --skip-generated -s standard -s default -s "prefix(github.com/fraima/key-keeper)" . + gci write --skip-generated -s standard -s default -s "prefix($(module))" . linter: docker run --rm -v $(pwd):/app -w /app golangci/golangci-lint:v1.49.0 golangci-lint run -v \ No newline at end of file From d536ddc9f844edac22ec278c7d20fbb074e77b00 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Wed, 30 Nov 2022 13:42:57 +0300 Subject: [PATCH 206/220] update Dockerfile --- .release | 1 - Dockerfile | 8 +++++--- Makefile | 7 +++++-- 3 files changed, 10 insertions(+), 6 deletions(-) delete mode 100644 .release diff --git a/.release b/.release deleted file mode 100644 index 60453e6..0000000 --- a/.release +++ /dev/null @@ -1 +0,0 @@ -v1.0.0 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 9622221..d0bfb4d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,8 +14,10 @@ RUN go install -ldflags "-s \ -X main.Version=${VERSION}" \ /app/cmd/${PROJECT} -FROM alpine:3.15.0 +FROM alpine:3.16.0 -COPY --from=builder /go/bin/${PROJECT} /usr/local/bin/${PROJECT} +ARG PROJECT + +COPY --from=builder /go/bin/${PROJECT} /usr/local/bin/app -ENTRYPOINT [${PROJECT}] \ No newline at end of file +ENTRYPOINT ["app"] \ No newline at end of file diff --git a/Makefile b/Makefile index 7c4264a..dbdaaaf 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,6 @@ -project = key-keeper#change for new project +#change for new project +project = key-keeper +#change for new release release = v1.0.0 tag = $(DOCKER_USER)/$(project):$(release) @@ -7,7 +9,8 @@ module = $(shell head -n 1 1 go.mod| awk '{print $2}') build-and-push: docker build -t $(tag) --build-arg VERSION=$(release) --build-arg PROJECT=$(project) -f Dockerfile . - # docker image push $(tag) + docker image push $(tag) + echo $(tag) formatting: go fmt ./... From 48ca7a74f79aeb8519a3482ba463a1cbf445bb27 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Thu, 1 Dec 2022 11:05:10 +0300 Subject: [PATCH 207/220] FD-22 cn with hostname placeholder --- internal/issuer/vault/certificate.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/internal/issuer/vault/certificate.go b/internal/issuer/vault/certificate.go index 9597c32..7617c98 100644 --- a/internal/issuer/vault/certificate.go +++ b/internal/issuer/vault/certificate.go @@ -13,6 +13,7 @@ import ( "os/exec" "path" "regexp" + "strings" "time" "go.uber.org/zap" @@ -77,7 +78,13 @@ func (s *vault) createCSR(spec config.Spec) (crt, key []byte, err error) { return } - ips, err := s.getIPAddresses(spec.IPAddresses) + commonName, err := getCommonName(spec.Subject.CommonName) + if err != nil { + err = fmt.Errorf("get common name: %w", err) + return + } + + ips, err := getIPAddresses(spec.IPAddresses) if err != nil { err = fmt.Errorf("get ip addresses: %w", err) return @@ -91,7 +98,7 @@ func (s *vault) createCSR(spec config.Spec) (crt, key []byte, err error) { template := x509.CertificateRequest{ Subject: pkix.Name{ - CommonName: spec.Subject.CommonName, + CommonName: commonName, Country: spec.Subject.Country, Locality: spec.Subject.Locality, Organization: spec.Subject.Organization, @@ -127,7 +134,12 @@ func (s *vault) createCSR(spec config.Spec) (crt, key []byte, err error) { return } -func (s *vault) getIPAddresses(cfg config.IPAddresses) ([]net.IP, error) { +func getCommonName(src string) (string, error) { + hostname, err := os.Hostname() + return strings.ReplaceAll(src, "$HOSTNAME", hostname), err +} + +func getIPAddresses(cfg config.IPAddresses) ([]net.IP, error) { ipAddresses := make(map[string]net.IP) for _, ip := range cfg.Static { From 84775f144b40208595b8ae4ae78d0ae68d69ce49 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Wed, 7 Dec 2022 12:14:42 +0300 Subject: [PATCH 208/220] up Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index dbdaaaf..86f1f01 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ release = v1.0.0 tag = $(DOCKER_USER)/$(project):$(release) pwd = $(shell pwd) -module = $(shell head -n 1 1 go.mod| awk '{print $2}') +module = $(shell go list -m) build-and-push: docker build -t $(tag) --build-arg VERSION=$(release) --build-arg PROJECT=$(project) -f Dockerfile . From 7a2f4b25af1415a156927cc9d5ca93df875e3b13 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Fri, 9 Dec 2022 17:49:14 +0300 Subject: [PATCH 209/220] fix get ca --- cmd/key-keeper/main.go | 4 ++-- internal/issuer/vault/ca-certificate.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/key-keeper/main.go b/cmd/key-keeper/main.go index 9d5f4a3..d1f78ce 100644 --- a/cmd/key-keeper/main.go +++ b/cmd/key-keeper/main.go @@ -28,8 +28,8 @@ func main() { zap.ReplaceGlobals(logger) var configDir, configNameLayout string - flag.StringVar(&configDir, "config-dir", "", "path to dir with configs") - flag.StringVar(&configNameLayout, "config-regexp", "", "regexp for config files names") + flag.StringVar(&configDir, "config-dir", "/home/geo/projects/fraima/key-keeper/test/", "path to dir with configs") + flag.StringVar(&configNameLayout, "config-regexp", "test.yaml", "regexp for config files names") flag.Parse() if configDir == "" { diff --git a/internal/issuer/vault/ca-certificate.go b/internal/issuer/vault/ca-certificate.go index 72d70a5..6a1b802 100644 --- a/internal/issuer/vault/ca-certificate.go +++ b/internal/issuer/vault/ca-certificate.go @@ -44,7 +44,7 @@ func (s *vault) ensureCA(cert config.Certificate) { func (s *vault) checkCA(cert config.Certificate, l *zap.Logger) ([]byte, []byte, error) { crt, key, err := s.readCA(s.caPath) - if crt == nil || key == nil { + if crt == nil { return nil, nil, fmt.Errorf("crt or key is empty path: %s", s.caPath) } if err == nil { From 1599c2aa7cbb8047db1922af47e20cefb69b96e8 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Fri, 9 Dec 2022 17:59:44 +0300 Subject: [PATCH 210/220] dns names --- internal/config/config.go | 1 - internal/issuer/vault/certificate.go | 14 +++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/internal/config/config.go b/internal/config/config.go index 1e071f9..bdd38e5 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -56,7 +56,6 @@ func (s *config) GetNewConfig() (cfg Config, err error) { cfg.Resource.Secrets = append(cfg.Resource.Secrets, tmpCfg.Resource.Secrets...) s.oldConfig[path] = struct{}{} } - return } diff --git a/internal/issuer/vault/certificate.go b/internal/issuer/vault/certificate.go index 7617c98..21300d3 100644 --- a/internal/issuer/vault/certificate.go +++ b/internal/issuer/vault/certificate.go @@ -197,14 +197,14 @@ func getIPAddresses(cfg config.IPAddresses) ([]net.IP, error) { } func getDNSNames(src []string) ([]string, error) { - var err error - for i, hostname := range src { - if hostname == "$HOSTNAME" { - src[i], err = os.Hostname() - break - } + hostname, err := os.Hostname() + if err != nil { + return nil, err + } + for i := range src { + src[i] = strings.ReplaceAll(src[i], "$HOSTNAME", hostname) } - return src, err + return src, nil } func inSlice(str string, sl []string) bool { From fdef8ead05a5484068dcdcdb8bc91bca65fb53c4 Mon Sep 17 00:00:00 2001 From: irbgeo Date: Tue, 20 Dec 2022 15:17:19 +0300 Subject: [PATCH 211/220] up --- cmd/key-keeper/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/key-keeper/main.go b/cmd/key-keeper/main.go index d1f78ce..9d5f4a3 100644 --- a/cmd/key-keeper/main.go +++ b/cmd/key-keeper/main.go @@ -28,8 +28,8 @@ func main() { zap.ReplaceGlobals(logger) var configDir, configNameLayout string - flag.StringVar(&configDir, "config-dir", "/home/geo/projects/fraima/key-keeper/test/", "path to dir with configs") - flag.StringVar(&configNameLayout, "config-regexp", "test.yaml", "regexp for config files names") + flag.StringVar(&configDir, "config-dir", "", "path to dir with configs") + flag.StringVar(&configNameLayout, "config-regexp", "", "regexp for config files names") flag.Parse() if configDir == "" { From bf1f92bd88e3ef438e7872ea5f0b9d734af8a7e4 Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Sun, 9 Apr 2023 01:49:13 +0300 Subject: [PATCH 212/220] [main] --- .github/workflows/release.yml | 50 +++++++++++++++++++++++++++++++++ .gitignore | 3 +- Makefile | 5 +++- hack/release.sh | 52 +++++++++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 hack/release.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..92cc572 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,50 @@ +name: release +on: + push: + tags: + - "*" +jobs: + publish: + name: release + runs-on: ubuntu-20.04 + steps: + - uses: actions/setup-go@v2 + with: + go-version: '1.19' + + - name: Set env + shell: bash + run: | + echo "GOPATH=${{ github.workspace }}" >> $GITHUB_ENV + echo "${{ github.workspace }}/bin" >> $GITHUB_PATH + + - uses: actions/cache@v2 + with: + path: | + ~/go/pkg/mod + ~/.cache/go-build + key: go-release-${{ hashFiles('**/go.sum') }} + restore-keys: go-release- + + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + path: src/github.com/fraima/key-keeper + + - run: | + make release + env: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + working-directory: src/github.com/fraima/key-keeper + + - uses: ncipollo/release-action@v1 + with: + allowUpdates: true + artifacts: src/github.com/fraima/key-keeper/_output/releases/* + bodyFile: src/github.com/fraima/key-keeper/release-notes.md + token: ${{ secrets.GH_TOKEN }} + + - uses: actions/upload-artifact@v2 + with: + name: build-artifacts + path: src/github.com/fraima/key-keeper/_output \ No newline at end of file diff --git a/.gitignore b/.gitignore index fc90926..79d4c36 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ test/ key-keeper role_id secret_id -test.yaml \ No newline at end of file +test.yaml +src/_output/* \ No newline at end of file diff --git a/Makefile b/Makefile index 86f1f01..44bd482 100644 --- a/Makefile +++ b/Makefile @@ -18,4 +18,7 @@ formatting: gci write --skip-generated -s standard -s default -s "prefix($(module))" . linter: - docker run --rm -v $(pwd):/app -w /app golangci/golangci-lint:v1.49.0 golangci-lint run -v \ No newline at end of file + docker run --rm -v $(pwd):/app -w /app golangci/golangci-lint:v1.49.0 golangci-lint run -v + +release: + sh hack/release.sh diff --git a/hack/release.sh b/hack/release.sh new file mode 100644 index 0000000..90f825f --- /dev/null +++ b/hack/release.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash + +# Copyright 2018 The Kubernetes Authors. +# +# Licensed 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. + +VERSION=$(git describe --abbrev=0 --tag) + +TOOLS_ROOT="$GOPATH/src/$PROJECT" +OUTPUTDIR=$TOOLS_ROOT/_output/releases +mkdir -p "$OUTPUTDIR" + +GO_LDFLAGS="-X ${PROJECT}/pkg/version.Version=${VERSION}" + +os="linux" +arch=$(basename "linux/amd64") + +KEY_KEEPER_BIN="key-keeper" + +output_bin=${TOOLS_ROOT}/_output/bin/$arch-$os/${KEY_KEEPER_BIN} + +GOARCH="$arch" GOOS="$os" CGO_ENABLED=0 go build \ +-o ${output_bin} \ +-ldflags "${GO_LDFLAGS}" \ +cmd/key-keeper/main.go + +file ${output_bin} +tar zcf "$OUTPUTDIR/key-keeper-$VERSION-$os-$arch.tar.gz" \ +-C ${TOOLS_ROOT}/_output/bin/$arch-$os \ +${KEY_KEEPER_BIN} + + +printf "\n## Downloads\n\n" | tee -a release-notes.md +echo "| file | sha256 | sha512" | tee -a release-notes.md +echo "| ---- | ------ | ------" | tee -a release-notes.md + +for file in "$OUTPUTDIR"/*.tar.gz; do + SHA256=$(shasum -a 256 "$file" | sed -e "s,$file,," | awk '{print $1}' | tee "$file.sha256") + SHA512=$(shasum -a 512 "$file" | sed -e "s,$file,," | awk '{print $1}' | tee "$file.sha512") + BASE=$(basename "$file") + echo "| $BASE | $SHA256 | $SHA512 |" | tee -a release-notes.md +done From 386b772b00e1898aceb8bf65f6f4d93eb6dd9fb2 Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Sun, 9 Apr 2023 01:54:54 +0300 Subject: [PATCH 213/220] [main] --- .github/workflows/release.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 92cc572..c1a8c3b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -43,6 +43,8 @@ jobs: artifacts: src/github.com/fraima/key-keeper/_output/releases/* bodyFile: src/github.com/fraima/key-keeper/release-notes.md token: ${{ secrets.GH_TOKEN }} + env: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} - uses: actions/upload-artifact@v2 with: From e222ca0d124143b400722e7b843a7bdb328f4de4 Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Sun, 9 Apr 2023 01:58:34 +0300 Subject: [PATCH 214/220] [main] --- .github/workflows/release.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c1a8c3b..3ddaa21 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,6 +7,8 @@ jobs: publish: name: release runs-on: ubuntu-20.04 + permissions: + contents: write steps: - uses: actions/setup-go@v2 with: From 43761238d03a17d7e472f70b4d5c63fcf54575f6 Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Sun, 9 Apr 2023 02:00:23 +0300 Subject: [PATCH 215/220] [main] --- .github/workflows/release.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3ddaa21..feb41d2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -44,9 +44,6 @@ jobs: allowUpdates: true artifacts: src/github.com/fraima/key-keeper/_output/releases/* bodyFile: src/github.com/fraima/key-keeper/release-notes.md - token: ${{ secrets.GH_TOKEN }} - env: - GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} - uses: actions/upload-artifact@v2 with: From 18cdb95a8f50f5e4a4a10b08284769de475d9395 Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Sun, 9 Apr 2023 02:07:38 +0300 Subject: [PATCH 216/220] [main] --- hack/release.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hack/release.sh b/hack/release.sh index 90f825f..79c8aa9 100644 --- a/hack/release.sh +++ b/hack/release.sh @@ -14,8 +14,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +PROJECT="github.com/fraima/key-keeper" VERSION=$(git describe --abbrev=0 --tag) - +GOPATH="/home/dk/workspace/fraima/key-keeper" TOOLS_ROOT="$GOPATH/src/$PROJECT" OUTPUTDIR=$TOOLS_ROOT/_output/releases mkdir -p "$OUTPUTDIR" From 9f8b71804f76d516d216cc2c019b0bcb3d7ca203 Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Sun, 9 Apr 2023 02:10:15 +0300 Subject: [PATCH 217/220] [main] --- hack/release.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hack/release.sh b/hack/release.sh index 79c8aa9..b5a5cb8 100644 --- a/hack/release.sh +++ b/hack/release.sh @@ -16,7 +16,7 @@ PROJECT="github.com/fraima/key-keeper" VERSION=$(git describe --abbrev=0 --tag) -GOPATH="/home/dk/workspace/fraima/key-keeper" + TOOLS_ROOT="$GOPATH/src/$PROJECT" OUTPUTDIR=$TOOLS_ROOT/_output/releases mkdir -p "$OUTPUTDIR" From 110b6be12c3c6083dfce686502beb820ddcb380e Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Sun, 25 Jun 2023 15:40:32 +0300 Subject: [PATCH 218/220] =?UTF-8?q?[KK-10]=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D1=8F=D0=B5=D1=82=20=D0=B2=20=D1=80=D0=B8=D0=B4?= =?UTF-8?q?=D0=BC=D0=B8=20=D0=B8=D0=BD=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D1=8E=20=D0=BF=D0=BE=20spec.usage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 924a447..31731fc 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,7 @@ issuers: | `.spec.ipAddresses.interfaces` | list | список ip адресов, взятый с интерфейсов хоста, попадет в ipSans | | `.spec.ipAddresses.dnsLookup` | list | список ip адресов, взятый из функции dnslookup статичной A записи, попадет в ipSans | | `.spec.ttl` | string | срок на который заказывается сертификат | +| `.spec.usage` | list | [Key usage extensions and extended key usage](https://help.hcltechsw.com/domino/10.0.1/admin/conf_keyusageextensionsandextendedkeyusage_r.html) | | `.hostPath` | string | путь в локальной файловой системе, где будет сохранен сертификат | | `.withUpdate` | bool | данный параметр создаст сертификат без последующего перевыпуска | | `.updateBefore` | string | время до истечения сертификата - при достижении сертификат перевыпустится | From 1ab022eeb3f633d66fc648f86b1cd594a5ae8cc8 Mon Sep 17 00:00:00 2001 From: Dobry-kot Date: Sun, 25 Jun 2023 15:42:22 +0300 Subject: [PATCH 219/220] [KK-10] fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 31731fc..49ef5a8 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ issuers: | `.spec.ipAddresses.interfaces` | list | список ip адресов, взятый с интерфейсов хоста, попадет в ipSans | | `.spec.ipAddresses.dnsLookup` | list | список ip адресов, взятый из функции dnslookup статичной A записи, попадет в ipSans | | `.spec.ttl` | string | срок на который заказывается сертификат | -| `.spec.usage` | list | [Key usage extensions and extended key usage](https://help.hcltechsw.com/domino/10.0.1/admin/conf_keyusageextensionsandextendedkeyusage_r.html) | +| `.spec.usage` | list | [Key usage extensions and extended key usage](https://help.hcltechsw.com/domino/10.0.1/admin/conf_keyusageextensionsandextendedkeyusage_r.html)| | `.hostPath` | string | путь в локальной файловой системе, где будет сохранен сертификат | | `.withUpdate` | bool | данный параметр создаст сертификат без последующего перевыпуска | | `.updateBefore` | string | время до истечения сертификата - при достижении сертификат перевыпустится | From aba21895c7e3c442bae3819461a744e2d36b4df3 Mon Sep 17 00:00:00 2001 From: fraima <107264732+fraima@users.noreply.github.com> Date: Sun, 25 Jun 2023 15:48:40 +0300 Subject: [PATCH 220/220] [KK-10] fix link (#12) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 49ef5a8..0de0a97 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ issuers: | `.spec.ipAddresses.interfaces` | list | список ip адресов, взятый с интерфейсов хоста, попадет в ipSans | | `.spec.ipAddresses.dnsLookup` | list | список ip адресов, взятый из функции dnslookup статичной A записи, попадет в ipSans | | `.spec.ttl` | string | срок на который заказывается сертификат | -| `.spec.usage` | list | [Key usage extensions and extended key usage](https://help.hcltechsw.com/domino/10.0.1/admin/conf_keyusageextensionsandextendedkeyusage_r.html)| +| `.spec.usage` | list | [Key usage extensions and extended key usage](https://pkg.go.dev/crypto/x509#KeyUsage) | | `.hostPath` | string | путь в локальной файловой системе, где будет сохранен сертификат | | `.withUpdate` | bool | данный параметр создаст сертификат без последующего перевыпуска | | `.updateBefore` | string | время до истечения сертификата - при достижении сертификат перевыпустится |