This commit is contained in:
Paulo 2022-12-02 10:24:20 -07:00
Родитель 2aa3b7a04a
Коммит 2e92118ec9
6 изменённых файлов: 321 добавлений и 160 удалений

Просмотреть файл

@ -1,39 +1,50 @@
//module github.com/Azure/keyvaultcertdownloader/keyvaultcertdownloader
module keyvaultcertdownloader
go 1.18
require (
github.com/Azure/azure-sdk-for-go v67.0.0+incompatible
github.com/Azure/go-autorest/autorest v0.11.28
github.com/Azure/go-autorest/autorest/azure/auth v0.5.11
software.sslmate.com/src/go-pkcs12 v0.2.0
)
require github.com/Azure/azure-sdk-for-go v67.1.0+incompatible
require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest v0.11.28 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect
github.com/Azure/go-autorest/autorest/azure/auth v0.5.11 // indirect
github.com/Azure/go-autorest/autorest/azure/cli v0.4.5 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v0.7.0 // indirect
github.com/dimchansky/utfbom v1.1.1 // indirect
github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
github.com/google/uuid v1.1.1 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
golang.org/x/text v0.3.7 // indirect
software.sslmate.com/src/go-pkcs12 v0.2.0 // indirect
)
require (
internal/utils v1.0.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.0
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates v0.8.0
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.11.0
internal/corehelper v1.0.0
internal/iam v1.0.0
internal/models v1.0.0
internal/utils v1.0.0
)
replace (
internal/utils => ./internal/utils
internal/corehelper => ./internal/corehelper
internal/iam => ./internal/iam
internal/models => ./internal/models
)
internal/utils => ./internal/utils
)

Просмотреть файл

@ -1,5 +1,17 @@
github.com/Azure/azure-sdk-for-go v67.0.0+incompatible h1:SVBwznSETB0Sipd0uyGJr7khLhJOFRUEUb+0JgkCvDo=
github.com/Azure/azure-sdk-for-go v67.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v67.1.0+incompatible h1:oziYcaopbnIKfM69DL05wXdypiqfrUKdxUKrKpynJTw=
github.com/Azure/azure-sdk-for-go v67.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.1 h1:tz19qLF65vuu2ibfTqGVJxG/zZAI27NEIIbvAOQwYbw=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.1/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.0 h1:t/W5MYAuQy81cvM8VUNfRLzhtKpXhVUAN7Cd7KVbTyc=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.0/go.mod h1:NBanQUfSWiWn3QEpWDTCU0IjBECKOYvl2R8xdRtMtiM=
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/azcertificates v0.8.0 h1:edn/e2qs1fEkPHlZqbESJWhFai9Pk/UA5eiwFUA1nwI=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates v0.8.0/go.mod h1:8eUJPoEz7doIqSwW2pAvLGhEy3mDC9o/ToCa8OZy7go=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.11.0 h1:82w8tzLcOwDP/Q35j/wEBPt0n0kVC3cjtPdD62G8UAk=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.11.0/go.mod h1:S78i9yTr4o/nXlH76bKjGUye9Z2wSxO5Tz7GoDr4vfI=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0 h1:Lg6BW0VPmCwcMlvOviL3ruHFO+H9tZNqscK0AeuFjGM=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0/go.mod h1:9V2j0jn9jDEkCkv8w/bKTNppX/d0FVA1ud77xCIP4KA=
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.11.24/go.mod h1:G6kyRlFnTuSbEYkQGawPfsCswgme4iYf6rfSKUDzbCc=
@ -24,6 +36,8 @@ github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+Z
github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/AzureAD/microsoft-authentication-library-for-go v0.7.0 h1:VgSJlZH5u0k2qxSpqyghcFQKmvYckj46uymKK5XzkBM=
github.com/AzureAD/microsoft-authentication-library-for-go v0.7.0/go.mod h1:BDJ5qMFKx9DugEg3+uQSDCdbYPr5s9vBTrL9P8TpqOU=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
@ -31,8 +45,16 @@ github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU=
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
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/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@ -45,12 +67,18 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJ
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
software.sslmate.com/src/go-pkcs12 v0.2.0 h1:nlFkj7bTysH6VkC4fGphtjXRbezREPgrHuJG20hBGPE=
software.sslmate.com/src/go-pkcs12 v0.2.0/go.mod h1:23rNcYsMabIc1otwLpTkCCPwUq6kQsTyowttG/as0kQ=

Просмотреть файл

@ -0,0 +1,162 @@
// Copyright (c) Microsoft and contributors. All rights reserved.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
// Package that provides some core functionality functions.
package corehelper
import (
"context"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
"net/url"
"os"
"strings"
"github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates"
"github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets"
gpkcs12 "software.sslmate.com/src/go-pkcs12"
)
// GetBlocksFromPEM - Gets decoded data block from PEM
func GetBlocksFromPEM(data []byte, blocks []*pem.Block) []*pem.Block {
block, rest := pem.Decode(data)
if block == nil {
return blocks
}
blocks = append(blocks, block)
return GetBlocksFromPEM(rest, blocks)
}
// GetBlocksFromPCKS12 - Gets decoded data block from PKCS12
func GetBlocksFromPCKS12(certString string) (blocks []*pem.Block, err error) {
decodedData, _ := base64.StdEncoding.DecodeString(certString)
// Decoding PKCS12 blob
privateKey, firstCert, certList, err := gpkcs12.DecodeChain(decodedData, "")
if err != nil {
return nil, err
}
// Extracting private key and creating private key pem.block
privateKeyBytes, err := x509.MarshalPKCS8PrivateKey(privateKey)
if err != nil {
return nil, err
}
blocks = append(blocks, &pem.Block{Type: "PRIVATE KEY", Bytes: privateKeyBytes})
// Checking if first certificate is non-CA cert and converting to pem.block if true
if !firstCert.IsCA {
blocks = append(blocks, &pem.Block{Type: "CERTIFICATE", Bytes: firstCert.Raw})
return blocks, nil
}
// Iterating over the caCerts list since we cannot assume that cert returned by pkcs12.DecodeChain
// is the leaf certificate
for _, cert := range certList {
if !cert.IsCA {
blocks = append(blocks, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
break
}
}
return blocks, nil
}
// WritePEMfile - Writes the output PEM file
func WritePEMfile(filename string, certificate, privateKey interface{}) error {
f, err := os.Create(filename)
if err != nil {
return fmt.Errorf("unable to create pem file %v: %v", filename, err)
}
defer f.Close()
err = pem.Encode(f, &pem.Block{Type: certificate.(*pem.Block).Type, Bytes: certificate.(*pem.Block).Bytes})
if err != nil {
return fmt.Errorf("an error ocurred writting certificate to pem file %v", err)
}
err = pem.Encode(f, &pem.Block{Type: privateKey.(*pem.Block).Type, Bytes: privateKey.(*pem.Block).Bytes})
if err != nil {
return fmt.Errorf("an error ocurred writting private key to pem file %v", err)
}
return nil
}
// GetCertificateFromPEMBLocks - Gets a certificate from PEM Blocks
func GetCertificateFromPEMBLocks(blocks interface{}) (certificate interface{}, err error) {
for _, b := range blocks.([]*pem.Block) {
if strings.Contains(b.Type, "CERTIFICATE") {
x509cert, err := x509.ParseCertificate(b.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse certificate: %v", err)
}
if !x509cert.IsCA {
certificate = b
break
}
}
}
if certificate == nil {
return nil, fmt.Errorf("unable to find non-CA certificate")
}
return certificate, nil
}
// GetPrivateKeyFromPEMBlocks - Gets private key from PEM Blocks
func GetPrivateKeyFromPEMBlocks(blocks interface{}) (privateKey interface{}, err error) {
for _, b := range blocks.([]*pem.Block) {
if strings.Contains(b.Type, "PRIVATE KEY") {
privateKey = b
break
}
}
if privateKey == nil {
return nil, fmt.Errorf("unable to find private key")
}
return privateKey, nil
}
//
//!SECTION - SDK dependent functions
//
//!SECTION - Internal functions
func getAKVCertificateBundle(cntx context.Context, client azcertificates.Client, certURL url.URL) (azcertificates.CertificateBundle, error) {
cert, err := client.GetCertificate(cntx, certURL.Path, "", nil)
if err != nil {
return azcertificates.CertificateBundle{}, err
}
return cert, nil
}
//!SECTION - Public functions
// GetAKVCertificate - Gets a certificate from AKV
func GetAKVCertificate(cntx context.Context, client azsecrets.Client, certURL url.URL) (azsecrets.GetSecretRespose, error) {
certSecret, err := client.GetSecret(cntx, certURL.Path, "", nil)
if err != nil {
return azsecrets.SecretBundle{}, err
}
return certSecret, nil
}
// GetAKVCertThumbprint - Gets thumbprint from bundle
func GetAKVCertThumbprint(cntx context.Context, client azcertificates.Client, certURL url.URL) (thumbprint string, err error) {
certBundle, err := getAKVCertificateBundle(cntx, client, certURL)
if err != nil {
return "", fmt.Errorf("unable to get certificate bundle: %v", err)
}
return *certBundle.X509Thumbprint, nil
}

Просмотреть файл

@ -0,0 +1,18 @@
module github.com/Azure/keyvaultcertdownloader/keyvaultcertdownloader/internal/corehelper
go 1.18
require (
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates v0.8.0
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.11.0
software.sslmate.com/src/go-pkcs12 v0.2.0
)
require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0 // indirect
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect
golang.org/x/text v0.3.7 // indirect
)

Просмотреть файл

@ -0,0 +1,39 @@
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.1 h1:tz19qLF65vuu2ibfTqGVJxG/zZAI27NEIIbvAOQwYbw=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.1/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8=
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/azcertificates v0.8.0 h1:edn/e2qs1fEkPHlZqbESJWhFai9Pk/UA5eiwFUA1nwI=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates v0.8.0/go.mod h1:8eUJPoEz7doIqSwW2pAvLGhEy3mDC9o/ToCa8OZy7go=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.11.0 h1:82w8tzLcOwDP/Q35j/wEBPt0n0kVC3cjtPdD62G8UAk=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.11.0/go.mod h1:S78i9yTr4o/nXlH76bKjGUye9Z2wSxO5Tz7GoDr4vfI=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0 h1:Lg6BW0VPmCwcMlvOviL3ruHFO+H9tZNqscK0AeuFjGM=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0/go.mod h1:9V2j0jn9jDEkCkv8w/bKTNppX/d0FVA1ud77xCIP4KA=
github.com/AzureAD/microsoft-authentication-library-for-go v0.5.1 h1:BWe8a+f/t+7KY7zH2mqygeUD0t8hNFXe08p1Pb3/jKE=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/dnaeon/go-vcr v1.1.0 h1:ReYa/UBrRyQdant9B4fNHGoCNKw6qh6P0fsdGmZpR7c=
github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.6/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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
software.sslmate.com/src/go-pkcs12 v0.2.0 h1:nlFkj7bTysH6VkC4fGphtjXRbezREPgrHuJG20hBGPE=
software.sslmate.com/src/go-pkcs12 v0.2.0/go.mod h1:23rNcYsMabIc1otwLpTkCCPwUq6kQsTyowttG/as0kQ=

Просмотреть файл

@ -11,10 +11,7 @@ package main
import (
"context"
"crypto/x509"
"encoding/base64"
"encoding/hex"
"encoding/pem"
"flag"
"fmt"
"log"
@ -22,11 +19,12 @@ import (
"os"
"strings"
"internal/corehelper"
"internal/utils"
"github.com/Azure/azure-sdk-for-go/profiles/latest/keyvault/keyvault"
kvauth "github.com/Azure/azure-sdk-for-go/services/keyvault/auth"
"software.sslmate.com/src/go-pkcs12"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates"
"github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets"
)
const (
@ -40,11 +38,13 @@ const (
ERR_X509_THUMBPRINT = 9
ERR_OUTPUTFOLDER_NOT_FOUND = 10
ERR_INVALID_AZURE_ENVIRONMENT = 11
ERR_CREDENTIALS = 12
)
var (
validEnvironments = []string{"AZUREPUBLICCLOUD", "AZUREUSGOVERNMENTCLOUD", "AZUREGERMANCLOUD", "AZURECHINACLOUD"}
certURL = flag.String("certurl", "", "certificate URL, e.g. \"https://mykeyvault.vault.azure.net/mycertificate\"")
keyVaultUrl = ""
outputFolder = flag.String("outputfolder", "", "folder where PEM file with certificate and private key will be saved")
environment = flag.String("environment", "AZUREPUBLICCLOUD", fmt.Sprintf("valid azure cloud environments: %v", validEnvironments))
cmdlineversion = flag.Bool("version", false, "shows current tool version")
@ -97,6 +97,7 @@ func main() {
exitCode = ERR_INVALID_URL
return
}
keyVaultUrl := fmt.Sprintf("%v://%v/", u.Scheme, u.Hostname())
utils.PrintHeader(fmt.Sprintf("keyvaultcertdownloader - Downloads a certificate from Azure KeyVault saving as PEM file - v%v", version))
@ -104,21 +105,48 @@ func main() {
utils.ConsoleOutput(fmt.Sprintf("Using Certificate URL: %v", *certURL), stdout)
utils.ConsoleOutput(fmt.Sprintf("Environment: %v", *environment), stdout)
utils.ConsoleOutput("Getting authorizer", stdout)
os.Setenv("AZURE_ENVIRONMENT", *environment)
authorizer, err := kvauth.NewAuthorizerFromEnvironment()
//utils.ConsoleOutput("Checking if this session needs to rely on AD Workload Identity webhook", stdout)
// client := keyvault.New()
// var authorizer autorest.Authorizer
tokenFilePath := os.Getenv("AZURE_FEDERATED_TOKEN_FILE")
if tokenFilePath == "" {
// utils.ConsoleOutput("Getting authorizer", stdout)
// os.Setenv("AZURE_ENVIRONMENT", *environment)
// authorizer, err = kvauth.NewAuthorizerFromEnvironment()
// if err != nil {
// utils.ConsoleOutput(fmt.Sprintf("<error> unable to create vault authorizer: %v\n", err), stderr)
// exitCode = ERR_AUTHORIZER
// return
// }
// utils.ConsoleOutput("Creating KeyVault base client", stdout)
} else {
}
// client.Authorizer = authorizer
utils.ConsoleOutput("Obtaining credentials", stdout)
cred, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
utils.ConsoleOutput(fmt.Sprintf("<error> unable to create vault authorizer: %v\n", err), stderr)
exitCode = ERR_AUTHORIZER
utils.ConsoleOutput(fmt.Sprintf("<error> %v\n", err), stderr)
exitCode = ERR_CREDENTIALS
return
}
utils.ConsoleOutput("Creating KeyVault base client", stdout)
client := keyvault.New()
client.Authorizer = authorizer
utils.ConsoleOutput("Creating clients", stdout)
azsecretsClient, err := azsecrets.NewClient(keyVaultUrl, cred, nil)
if err != nil {
log.Fatalf("failed to create azsecrets client: %v", err)
}
azcertsClient, err := azcertificates.NewClient(keyVaultUrl, cred, nil)
if err != nil {
log.Fatalf("failed to create azcertificates client: %v", err)
}
utils.ConsoleOutput("Getting certificate thumbprint", stdout)
x509Thumbprint, err := getAKVCertThumbprint(cntx, client, *u)
x509Thumbprint, err := corehelper.GetAKVCertThumbprint(cntx, azcertsClient, *u)
if err != nil {
utils.ConsoleOutput(fmt.Sprintf("<error> %v\n", err), stderr)
exitCode = ERR_X509_THUMBPRINT
@ -139,7 +167,7 @@ func main() {
// Get cert as secret
utils.ConsoleOutput("Getting certificate as secret", stdout)
certAKV, err := getAKVCertificate(cntx, client, *u)
certAKV, err := corehelper.GetAKVCertificate(cntx, azsecretsClient, *u)
if err != nil {
utils.ConsoleOutput(fmt.Sprintf("<error> unable to get certificate: %v\n", err), stderr)
exitCode = ERR_GET_AKV_CERT_SECRET
@ -151,26 +179,26 @@ func main() {
// Getting PEM Blocks
var blocks interface{}
if *certAKV.ContentType == "application/x-pkcs12" {
blocks, _ = getBlocksFromPCKS12(*certAKV.Value)
blocks, _ = corehelper.GetBlocksFromPCKS12(*certAKV.Value)
} else if *certAKV.ContentType == "application/x-pem-file" {
blocks = getBlocksFromPEM([]byte(*certAKV.Value), nil)
blocks = corehelper.GetBlocksFromPEM([]byte(*certAKV.Value), nil)
}
privateKey, err := getPrivateKeyFromPEMBlocks(blocks)
privateKey, err := corehelper.GetPrivateKeyFromPEMBlocks(blocks)
if err != nil {
utils.ConsoleOutput(fmt.Sprintf("<error> %v\n", err), stderr)
exitCode = ERR_GET_PEM_PRIVATE_KEY
return
}
certificate, err := getCertificateFromPEMBLocks(blocks)
certificate, err := corehelper.GetCertificateFromPEMBLocks(blocks)
if err != nil {
utils.ConsoleOutput(fmt.Sprintf("<error> %v\n", err), stderr)
exitCode = ERR_GET_PEM_CERTIFICATE
return
}
err = writePEMfile(pemFileName, certificate, privateKey)
err = corehelper.WritePEMfile(pemFileName, certificate, privateKey)
if err != nil {
utils.ConsoleOutput(fmt.Sprintf("<error> %v\n", err), stderr)
exitCode = ERR_CREATE_PEM_FILE
@ -185,128 +213,3 @@ func exit(cntx context.Context, exitCode int) {
}
}
}
func getBlocksFromPEM(data []byte, blocks []*pem.Block) []*pem.Block {
block, rest := pem.Decode(data)
if block == nil {
return blocks
}
blocks = append(blocks, block)
return getBlocksFromPEM(rest, blocks)
}
func getBlocksFromPCKS12(certString string) (blocks []*pem.Block, err error) {
decodedData, _ := base64.StdEncoding.DecodeString(certString)
// Decoding PKCS12 blob
privateKey, firstCert, certList, err := pkcs12.DecodeChain(decodedData, "")
if err != nil {
return nil, err
}
// Extracting private key and creating private key pem.block
privateKeyBytes, err := x509.MarshalPKCS8PrivateKey(privateKey)
if err != nil {
return nil, err
}
blocks = append(blocks, &pem.Block{Type: "PRIVATE KEY", Bytes: privateKeyBytes})
// Checking if first certificate is non-CA cert and converting to pem.block if true
if !firstCert.IsCA {
blocks = append(blocks, &pem.Block{Type: "CERTIFICATE", Bytes: firstCert.Raw})
return blocks, nil
}
// Iterating over the caCerts list since we cannot assume that cert returned by pkcs12.DecodeChain
// is the leaf certificate
for _, cert := range certList {
if !cert.IsCA {
blocks = append(blocks, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
break
}
}
return blocks, nil
}
func getAKVCertificateBundle(cntx context.Context, client keyvault.BaseClient, certURL url.URL) (keyvault.CertificateBundle, error) {
cert, err := client.GetCertificate(cntx, fmt.Sprintf("https://%v", certURL.Host), strings.Replace(certURL.Path, "/", "", 1), "")
if err != nil {
return keyvault.CertificateBundle{}, err
}
return cert, nil
}
func getAKVCertificate(cntx context.Context, client keyvault.BaseClient, certURL url.URL) (keyvault.SecretBundle, error) {
certSecret, err := client.GetSecret(cntx, fmt.Sprintf("https://%v", certURL.Host), strings.Replace(certURL.Path, "/", "", 1), "")
if err != nil {
return keyvault.SecretBundle{}, err
}
return certSecret, nil
}
func writePEMfile(filename string, certificate, privateKey interface{}) error {
f, err := os.Create(filename)
if err != nil {
return fmt.Errorf("unable to create pem file %v: %v", filename, err)
}
defer f.Close()
err = pem.Encode(f, &pem.Block{Type: certificate.(*pem.Block).Type, Bytes: certificate.(*pem.Block).Bytes})
if err != nil {
return fmt.Errorf("an error ocurred writting certificate to pem file %v:", err)
}
err = pem.Encode(f, &pem.Block{Type: privateKey.(*pem.Block).Type, Bytes: privateKey.(*pem.Block).Bytes})
if err != nil {
return fmt.Errorf("an error ocurred writting private key to pem file %v:", err)
}
return nil
}
func getCertificateFromPEMBLocks(blocks interface{}) (certificate interface{}, err error) {
for _, b := range blocks.([]*pem.Block) {
if strings.Contains(b.Type, "CERTIFICATE") {
x509cert, err := x509.ParseCertificate(b.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse certificate: %v", err)
}
if x509cert.IsCA == false {
certificate = b
break
}
}
}
if certificate == nil {
return nil, fmt.Errorf("unable to find non-CA certificate")
}
return certificate, nil
}
func getPrivateKeyFromPEMBlocks(blocks interface{}) (privateKey interface{}, err error) {
for _, b := range blocks.([]*pem.Block) {
if strings.Contains(b.Type, "PRIVATE KEY") {
privateKey = b
break
}
}
if privateKey == nil {
return nil, fmt.Errorf("unable to find private key")
}
return privateKey, nil
}
func getAKVCertThumbprint(cntx context.Context, client keyvault.BaseClient, certURL url.URL) (thumbprint string, err error) {
certBundle, err := getAKVCertificateBundle(cntx, client, certURL)
if err != nil {
return "", fmt.Errorf("unable to get certificate bundle: %v", err)
}
return *certBundle.X509Thumbprint, nil
}