* adding az sdk dependencies and tidying mod file

* adding keyvault shim

* example usage application for kv shim

* adding tests, cleaning up

* fixing linter errors

* updating go mod
This commit is contained in:
Ramiro 2022-06-02 17:21:57 -07:00 коммит произвёл GitHub
Родитель c3e709d2af
Коммит 5e6f76aaf7
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
7 изменённых файлов: 484 добавлений и 40 удалений

76
go.mod
Просмотреть файл

@ -3,14 +3,14 @@ module github.com/Azure/azure-container-networking
go 1.18
require (
code.cloudfoundry.org/clock v1.0.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.0.0
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.7.1
github.com/Masterminds/semver v1.5.0
github.com/Microsoft/go-winio v0.4.17
github.com/Microsoft/hcsshim v0.8.23
github.com/avast/retry-go/v3 v3.1.1
github.com/billgraziano/dpapi v0.4.0
github.com/containernetworking/cni v0.8.1
github.com/docker/docker v20.10.8+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/libnetwork v0.8.0-dev.2.0.20210525090646-64b7a4574d14
github.com/golang/mock v1.6.0
github.com/golang/protobuf v1.5.2
@ -18,7 +18,6 @@ require (
github.com/google/uuid v1.3.0
github.com/gorilla/mux v1.8.0
github.com/hashicorp/go-version v1.5.0
github.com/ishidawataru/sctp v0.0.0-20210226210310-f2269e66cdee // indirect
github.com/microsoft/ApplicationInsights-Go v0.4.4
github.com/nxadm/tail v1.4.8
github.com/onsi/ginkgo v1.16.5
@ -30,9 +29,8 @@ require (
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.12.0
github.com/stretchr/testify v1.7.1
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect
go.uber.org/zap v1.21.0
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
google.golang.org/grpc v1.46.2
google.golang.org/protobuf v1.28.0
k8s.io/api v0.24.1
@ -40,35 +38,60 @@ require (
k8s.io/apimachinery v0.24.1
k8s.io/client-go v0.24.1
k8s.io/klog v1.0.0
k8s.io/klog/v2 v2.60.1
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9
sigs.k8s.io/controller-runtime v0.12.1
sigs.k8s.io/yaml v1.3.0
)
require (
github.com/avast/retry-go/v3 v3.1.1
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.5.0 // indirect
)
require (
code.cloudfoundry.org/clock v1.0.0 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/containerd/cgroups v1.0.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/docker/docker v20.10.8+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/emicklei/go-restful v2.9.5+incompatible // indirect
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/go-logr/logr v1.2.0 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.5 // indirect
github.com/go-openapi/swag v0.19.14 // indirect
github.com/gofrs/uuid v3.3.0+incompatible // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/gnostic v0.5.7-v3refs // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hpcloud/tail v1.0.0 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/ishidawataru/sctp v0.0.0-20210226210310-f2269e66cdee // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/labstack/echo/v4 v4.7.2
github.com/labstack/gommon v0.3.1 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/moby/spdystream v0.2.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
@ -77,9 +100,16 @@ require (
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/subosito/gotenv v1.3.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.1 // indirect
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect
go.opencensus.io v0.23.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-20220511200225-c6db032c6c88
golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 // indirect
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect
@ -93,39 +123,9 @@ require (
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0 // indirect
k8s.io/component-base v0.24.1 // indirect
k8s.io/klog/v2 v2.60.1
k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
)
require go.uber.org/zap v1.21.0
require (
github.com/gofrs/uuid v3.3.0+incompatible // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
)
require (
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/emicklei/go-restful v2.9.5+incompatible // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.5 // indirect
github.com/go-openapi/swag v0.19.14 // indirect
github.com/google/gnostic v0.5.7-v3refs // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/labstack/echo/v4 v4.7.2
github.com/labstack/gommon v0.3.1 // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pelletier/go-toml/v2 v2.0.1 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.1 // indirect
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
)
replace (

19
go.sum
Просмотреть файл

@ -44,7 +44,17 @@ code.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c/go.mod h1:QD9Lzhd
code.cloudfoundry.org/clock v1.0.0 h1:kFXWQM4bxYvdBw2X8BbBeXwQNgfoWv1vqAk2ZZyBN2o=
code.cloudfoundry.org/clock v1.0.0/go.mod h1:QD9Lzhd/ux6eNQVUDVRJX/RKTigpewimNYBi7ivZKY8=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/azure-sdk-for-go v16.2.1+incompatible h1:KnPIugL51v3N3WwvaSmZbxukD1WuWXOiE9fRdu32f2I=
github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.0.0 h1:sVPhtT2qjO86rTUaWMr4WoES4TkjGnzcioXcnHV9s5k=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.0.0/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.0.0 h1:Yoicul8bnVdQrhDMTHxdEckRGX01XvwXDHUT9zYZ3k0=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.7.1 h1:X7FHRMKr0u5YiPnD6L/nqG64XBOcK0IYavhAHBQEmms=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.7.1/go.mod h1:WcC2Tk6JyRlqjn2byvinNnZzgdXmZ1tOiIOWNh1u0uA=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.5.0 h1:9cn6ICCGiWFNA/slKnrkf+ENyvaCRKHtuoGtnLIAgao=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.5.0/go.mod h1:9V2j0jn9jDEkCkv8w/bKTNppX/d0FVA1ud77xCIP4KA=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
@ -60,6 +70,7 @@ github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935
github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0 h1:WVsrXCnHlDDX8ls+tootqRE87/hL9S/g4ewig9RsD/c=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
@ -259,6 +270,7 @@ github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
github.com/dnaeon/go-vcr v1.1.0 h1:ReYa/UBrRyQdant9B4fNHGoCNKw6qh6P0fsdGmZpR7c=
github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
@ -364,6 +376,7 @@ github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@ -550,6 +563,7 @@ github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
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/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/labstack/echo/v4 v4.7.2 h1:Kv2/p8OaQ+M6Ex4eGimg9b9e6icoxA42JSlOR3msKtI=
github.com/labstack/echo/v4 v4.7.2/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
@ -663,6 +677,7 @@ github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko
github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU=
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@ -898,8 +913,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA=
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88 h1:Tgea0cVUD0ivh5ADBX4WwuI12DUd2to3nCYe2eayMIw=
golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=

147
keyvault/_example/main.go Normal file
Просмотреть файл

@ -0,0 +1,147 @@
package main
import (
"context"
"crypto/tls"
"crypto/x509"
"flag"
"fmt"
"io"
"net/http"
"os"
"time"
"github.com/Azure/azure-container-networking/keyvault"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
const serverAddr = "127.0.0.1:9005"
var logger *zap.Logger
func mustArgs() (kvURL string, kvCert string) {
flag.StringVar(&kvURL, "keyvault-url", "", "keyvault url")
flag.StringVar(&kvCert, "keyvault-cert-name", "", "keyvault certificate name")
flag.Parse()
if kvURL == "" || kvCert == "" {
flag.Usage()
os.Exit(1)
}
core := zapcore.NewCore(zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig()), os.Stdout, zap.DebugLevel)
logger = zap.New(core)
return
}
// you must be logged in via the az cli and have proper permissions to a keyvault to run this example
func main() {
kvURL, kvCert := mustArgs()
cred, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
logger.Fatal("could not create credentials", zap.Error(err))
}
kvs, err := keyvault.NewShim(kvURL, cred)
if err != nil {
logger.Fatal("could not create keyvault client", zap.Error(err))
}
tlsCert, err := kvs.GetLatestTLSCertificate(context.TODO(), kvCert)
if err != nil {
logger.Fatal("could not get tls cert from keyvault", zap.Error(err))
}
clientTLSConfig, err := createClientTLSConfig(tlsCert)
if err != nil {
logger.Fatal("could not create client tls config", zap.Error(err))
}
server := http.Server{
Addr: serverAddr,
Handler: http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
_, _ = writer.Write([]byte("hello"))
}),
TLSConfig: &tls.Config{
Certificates: []tls.Certificate{tlsCert},
ClientCAs: clientTLSConfig.RootCAs,
ClientAuth: tls.RequireAndVerifyClientCert,
},
}
go func() {
if err := server.ListenAndServeTLS("", ""); err != nil {
logger.Fatal("could not serve tls", zap.Error(err))
}
}()
// wait for a short time to allow server to start
time.Sleep(time.Second)
client := http.Client{
Transport: &http.Transport{
TLSClientConfig: clientTLSConfig,
},
}
addr := fmt.Sprintf("https://%s", serverAddr)
resp, err := client.Get(addr)
if err != nil {
logger.Fatal("could not get response", zap.String("host", addr), zap.Error(err))
}
printTLSConnState(resp.TLS)
bs, _ := io.ReadAll(resp.Body)
logger.Info("response from tls server", zap.String("body bytes", string(bs)))
}
func createClientTLSConfig(tlsCert tls.Certificate) (*tls.Config, error) {
certs := x509.NewCertPool()
if len(tlsCert.Certificate) == 1 { // self signed
cer, err := x509.ParseCertificate(tlsCert.Certificate[0])
if err != nil {
return nil, err
}
certs.AddCert(cer)
return &tls.Config{RootCAs: certs, ServerName: tlsCert.Leaf.Subject.CommonName}, nil
}
for i, bytes := range tlsCert.Certificate {
if i == 0 {
continue // skip leaf
}
cer, err := x509.ParseCertificate(bytes)
if err != nil {
return nil, err
}
certs.AddCert(cer)
}
return &tls.Config{Certificates: []tls.Certificate{tlsCert}, RootCAs: certs, ServerName: tlsCert.Leaf.Subject.CommonName}, nil
}
func printTLSConnState(connState *tls.ConnectionState) {
logger.Info("response tls connection state", zap.Object("conn state", loggableConnState(*connState)))
for i, cert := range connState.PeerCertificates {
logger.Info(fmt.Sprintf("peer certificate %d:", i), zap.Stringer("subject", cert.Subject), zap.Stringer("issuer", cert.Issuer))
}
for i, chain := range connState.VerifiedChains {
for j, cert := range chain {
logger.Info(fmt.Sprintf("chain %d, cert %d:", i, j), zap.Stringer("subject", cert.Subject), zap.Stringer("issuer", cert.Issuer))
}
}
}
type loggableConnState tls.ConnectionState
func (l loggableConnState) MarshalLogObject(encoder zapcore.ObjectEncoder) error {
encoder.AddString("server name", l.ServerName)
encoder.AddBool("handshake complete", l.HandshakeComplete)
encoder.AddInt("peer certificates", len(l.PeerCertificates))
encoder.AddInt("verified certificates", len(l.VerifiedChains))
return nil
}

158
keyvault/shim.go Normal file
Просмотреть файл

@ -0,0 +1,158 @@
package keyvault
import (
"context"
"crypto"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"strings"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets"
"github.com/pkg/errors"
"golang.org/x/crypto/pkcs12"
)
const (
pemContentType = "application/x-pem-file"
pkcs12ContentType = "application/x-pkcs12"
)
type secretFetcher interface {
GetSecret(ctx context.Context, secretName string, opts *azsecrets.GetSecretOptions) (azsecrets.GetSecretResponse, error)
}
// Shim provides convenience methods for working with KeyVault.
type Shim struct {
sf secretFetcher
}
// NewShim constructs a Shim for a KeyVault instance located at the provided url. The azcore.TokenCredential will
// only be used during method calls, it is not verified at initialization.
func NewShim(vaultURL string, cred azcore.TokenCredential) (*Shim, error) {
c, err := azsecrets.NewClient(vaultURL, cred, nil)
if err != nil {
return nil, errors.Wrap(err, "could not create new azsecrets.Client")
}
return &Shim{sf: c}, nil
}
// GetLatestTLSCertificate fetches the latest version of a keyvault certificate and transforms it into a usable tls.Certificate.
func (s *Shim) GetLatestTLSCertificate(ctx context.Context, certName string) (tls.Certificate, error) {
resp, err := s.sf.GetSecret(ctx, certName, nil)
if err != nil {
return tls.Certificate{}, errors.Wrap(err, "could not get secret")
}
pemBlocks, err := getPEMBlocks(*resp.Properties.ContentType, *resp.Value)
if err != nil {
return tls.Certificate{}, errors.Wrap(err, "could not get pem blocks")
}
var (
key crypto.PrivateKey
leaf *x509.Certificate
leafBytes []byte
cas [][]byte
)
for _, v := range pemBlocks {
switch {
case strings.Contains(v.Type, "PRIVATE KEY"):
key, err = parsePrivateKey(v.Bytes)
if err != nil {
return tls.Certificate{}, errors.Wrap(err, "could not parse private key")
}
case strings.Contains(v.Type, "CERTIFICATE"):
c, err := x509.ParseCertificate(v.Bytes)
if err != nil {
return tls.Certificate{}, errors.Wrap(err, "could not parse certificate")
}
if !c.IsCA {
leaf = c
leafBytes = v.Bytes
continue
}
cas = append(cas, v.Bytes)
}
}
if leaf == nil {
return tls.Certificate{}, errors.New("could not find leaf certificate")
}
return tls.Certificate{
PrivateKey: key,
Certificate: append([][]byte{leafBytes}, cas...),
Leaf: leaf,
}, nil
}
func getPEMBlocks(contentType, payload string) ([]*pem.Block, error) {
switch contentType {
case pkcs12ContentType:
return handlePFXBytes(payload)
case pemContentType:
return handlePEMBytes(payload)
}
return nil, errors.Errorf("unsupported content type %s", contentType)
}
func handlePFXBytes(v string) ([]*pem.Block, error) {
pfxBytes, err := base64.StdEncoding.DecodeString(v)
if err != nil {
return nil, errors.Wrap(err, "could not base64 decode keyvault.SecretBundle.Value")
}
bl, err := pkcs12.ToPEM(pfxBytes, "")
if err != nil {
return nil, errors.Wrap(err, "could not convert pfx to pem")
}
return bl, nil
}
func handlePEMBytes(v string) ([]*pem.Block, error) {
pemData := []byte(v)
var pemBlocks []*pem.Block
for {
b, rest := pem.Decode(pemData)
if b == nil {
break
}
pemBlocks = append(pemBlocks, b)
pemData = rest
}
if len(pemBlocks) == 0 {
return nil, errors.New("no pem blocks in input bytes")
}
return pemBlocks, nil
}
// from crypto/tls/tls.go
func parsePrivateKey(der []byte) (crypto.PrivateKey, error) {
if key, err := x509.ParsePKCS1PrivateKey(der); err == nil {
return key, nil
}
if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
switch key := key.(type) {
case *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey:
return key, nil
default:
return nil, errors.New("tls: found unknown private key type in PKCS#8 wrapping")
}
}
if key, err := x509.ParseECPrivateKey(der); err == nil {
return key, nil
}
return nil, errors.New("tls: failed to parse private key")
}

68
keyvault/shim_test.go Normal file
Просмотреть файл

@ -0,0 +1,68 @@
package keyvault
import (
"context"
"os"
"testing"
"github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestGetLatestTLSCert(t *testing.T) {
tests := []struct {
name string
certPath string
contentType string
}{
{
name: "pem encoding",
certPath: "testdata/dummy.pem",
contentType: pemContentType,
},
{
name: "pfx encoding",
certPath: "testdata/dummy.pfx",
contentType: pkcs12ContentType,
},
}
for _, ts := range tests {
ts := ts
t.Run(ts.name, func(t *testing.T) {
kvc := Shim{sf: newFakeSecretFetcher(ts.certPath, ts.contentType)}
cert, err := kvc.GetLatestTLSCertificate(context.TODO(), "dummy")
require.NoError(t, err)
assert.NotNil(t, cert.Leaf)
})
}
}
type fakeSecretFetcher struct {
certPath string
contentType string
}
func newFakeSecretFetcher(certPath, contentType string) *fakeSecretFetcher {
return &fakeSecretFetcher{certPath: certPath, contentType: contentType}
}
func (f *fakeSecretFetcher) GetSecret(_ context.Context, _ string, _ *azsecrets.GetSecretOptions) (azsecrets.GetSecretResponse, error) {
bs, err := os.ReadFile(f.certPath)
if err != nil {
return azsecrets.GetSecretResponse{}, errors.Wrap(err, "could not read file")
}
v := string(bs)
resp := azsecrets.GetSecretResponse{
Secret: azsecrets.Secret{
Properties: &azsecrets.Properties{ContentType: &f.contentType},
Value: &v,
},
}
return resp, nil
}

48
keyvault/testdata/dummy.pem поставляемый Normal file
Просмотреть файл

@ -0,0 +1,48 @@
-----BEGIN PRIVATE KEY-----
MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDQ15Os/mH6Z7px
Zv5ZdRQJyhmO8yzwKuvQi2q99cDQG1B6Kkh1R3rK/xwuIK2Yup5O8aFGOdHJZ3ly
9yNdVONyoOQLmvnyhV5vvs1HhdggvcvaT0BFjgTTedCMxUS+cVKXi7NsWUyCgba4
8+l9VRrykSenvx6W1wDAWTvuVBb+CU2A7SCsX1IspIY2z0xPnW62OCnAWJ1KAXJD
wxByVAoVP1CYUoFg+T/MXSHqDxjVQWZf+cvsQO3gF6/Qj8Zmbt4EYuztchYCa2RP
jzEATjPFnISdyfhmksLiAFcs4LSn7RjclASoprTOKpd/3YFMKAv04tqxVa3YZsOt
piTxpa2VAgMBAAECggEBAIWo80LMrDhvGsxpdnAalnCNgD4VNLWhQrt9/xsEphqK
4L7PQQCOdvBkxcxf7brJ9Xfg/a7MYo/cQcZqlZ+uLMO4ZTtoPIATC5XJL+iOqPyL
fGSEREY/1qbiV69AsfaQ4KNNLdAydt0v15oXwWANj+mfLRoXH6S6hiiU895cwzph
4X7H8nwx37hZ636Dav/q98vyd9RG5P4b3tv7bQ2kEIMxLEUSLZPwcataxIYBV7OH
vUYlXaO1qn7Er6XYU92bV4tZY2mpmFx2Sear2XG/Q+9yP/Bu668L+kO+/SpNa9Md
wPWV1vt+kRSNHgQJsVW5IDQMFAOdhqOaWnn66G2ErSECgYEA8rkU+XxO/pfkfm2n
CS7AMZhym4R7EQ+nQw3CmOvbOoBfLkU8nUGO1ODA7EjKRIyCvB8n6Mm74v81H5/+
zjl3Cb5z6E57hcrxM9lw+7voXi3Y7+iSKbqkAlGM7c8JLtJaOgZrt+BUSUMmJrKN
U2MFy69VMEyB0TvCU14WF8v+Oh8CgYEA3EQNK+YQcvaW5QSvHPlgJUubP5TJhVyT
Ip1OSnORrNI9pB4RoIJA7eZoTp/qK+YeHe/yPIfQyL1YDPnhVAgoSHDMT0JCSBxv
dRT3StCG54UsBo5b0QcYP0Wj5Ciayx3T+xZGTPg8eAYSiTVdhnAHHausYJ49Hnj+
GMlN7MWticsCgYEAwlfDHYeU0HDZ+QjfJ5ERPiSsDy1iRGTeLehEmaCvZgYHL8ss
H1WwgW57yjT2DzDaNLpVgCSWlch1xp6arJCCaYDe2XCNorC9tCA0QLtR8KaQ/naf
IV5Zl6moR3jwB1dR+wfNE+tAUXC8iVuJoOy2ZUI72XJItzk7/PhmhCNHqU0CgYEA
rW87+8vcOdlmOQ/2HldRWCxvIqIyBzs8c23vXnofQzgL5zTx5jOJkojwqrAJ/+Ti
4+myD+1U/SrxsM30mWkO5vNCPEpMzGDvdf47NYJ6JsRaRRNEwpLWicN458b9E1/6
MON6GVMAsfT+FWGasad2QuuRAEa4k0zrrnKbVArWuP8CgYEAun2ft8oybIQKuo0d
Hht5q/1gebBtYKIplgxGiAzlnuFlGzR8SFmUXnVJz7I4+4OndMd02TFDv4PX8fj3
7X2wtxeYtaWRBpfg/vz+Z6QMwxF0Sx9uRI9r05QntGec4ovg8rC9cr9WpBpwVmQf
gEkXqk6ZftIs56PG1z3QhlK1mbs=
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDQDCCAiigAwIBAgIQbkrr03sSQSShhzE0Zkk18zANBgkqhkiG9w0BAQsFADAS
MRAwDgYDVQQDEwdmb28uY29tMB4XDTIyMDQwNzE1NTg1OVoXDTIzMDQwNzE2MDg1
OVowEjEQMA4GA1UEAxMHZm9vLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBANDXk6z+YfpnunFm/ll1FAnKGY7zLPAq69CLar31wNAbUHoqSHVHesr/
HC4grZi6nk7xoUY50clneXL3I11U43Kg5Aua+fKFXm++zUeF2CC9y9pPQEWOBNN5
0IzFRL5xUpeLs2xZTIKBtrjz6X1VGvKRJ6e/HpbXAMBZO+5UFv4JTYDtIKxfUiyk
hjbPTE+dbrY4KcBYnUoBckPDEHJUChU/UJhSgWD5P8xdIeoPGNVBZl/5y+xA7eAX
r9CPxmZu3gRi7O1yFgJrZE+PMQBOM8WchJ3J+GaSwuIAVyzgtKftGNyUBKimtM4q
l3/dgUwoC/Ti2rFVrdhmw62mJPGlrZUCAwEAAaOBkTCBjjAOBgNVHQ8BAf8EBAMC
BaAwCQYDVR0TBAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYD
VR0RBAswCYIHZm9vLmNvbTAfBgNVHSMEGDAWgBT+rzOo+xdTZuRNNeo2U4/FAJDR
PDAdBgNVHQ4EFgQU/q8zqPsXU2bkTTXqNlOPxQCQ0TwwDQYJKoZIhvcNAQELBQAD
ggEBAB8tusBVjb+bksPrWZk/cNlYX2sqGjRHt4AZ5SW+VDhkLYlOpBENgDfkB5tS
Oz0WEv95wbWR/mzQv3AmhToPx/ZOUYWq+v1CBX6amkgPkf/5VLpk4fveVnkGLLhS
23/LeMZzPdVlKTsTYC1z0R2a/2Bd5XKnLT00cf3M1Gj/Ul3O4LmNDAY0KIohYljv
xje8Auhg1kbib7XbKr1KfPZztu4a0NmKvFqVgUooUOX9vFT1aF1GwENDezMf/NyJ
YB8x7dEOwYg8UBMA3PIOdobf0UKkVgnPh+kqKHL1/2ctYnNZvZkZ5f55+Ac0wTKm
6162fxN8Ri8B4A2YuGiWM+4MFPw=
-----END CERTIFICATE-----

8
keyvault/testdata/dummy.pfx поставляемый Normal file
Просмотреть файл

@ -0,0 +1,8 @@
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