diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 3267f65..aa5bdb5 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -16,7 +16,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v3 with: - go-version: 1.22.5 + go-version: 1.22.7 check-latest: true - name: Check out code uses: actions/checkout@v3 @@ -40,7 +40,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v3 with: - go-version: 1.22.5 + go-version: 1.22.7 check-latest: true - name: Check out code uses: actions/checkout@v3 @@ -57,7 +57,7 @@ jobs: uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: - go-version: 1.22.5 + go-version: 1.22.7 check-latest: true - name: Get govulncheck run: go install golang.org/x/vuln/cmd/govulncheck@latest diff --git a/go.work b/go.work index 2d95a92..c7fda9a 100644 --- a/go.work +++ b/go.work @@ -1,4 +1,4 @@ -go 1.21 +go 1.22.0 use ( ./kes diff --git a/kes/go.mod b/kes/go.mod index 17ccccf..02434be 100644 --- a/kes/go.mod +++ b/kes/go.mod @@ -1,6 +1,6 @@ module github.com/minio/kms-go/kes -go 1.21 +go 1.22.0 require ( aead.dev/mem v0.2.0 diff --git a/kms/client-examples_test.go b/kms/client-examples_test.go index 11e5670..a559348 100644 --- a/kms/client-examples_test.go +++ b/kms/client-examples_test.go @@ -14,11 +14,12 @@ import ( "log/slog" "time" + "aead.dev/mtls" "github.com/minio/kms-go/kms" ) func ExampleNewClient() { - key, err := kms.ParseAPIKey("k1:d7cY_5k8HbBGkZpoy2hGmvkxg83QDBXsA_nFXDfTk2E") + key, err := mtls.ParsePrivateKey("k1:d7cY_5k8HbBGkZpoy2hGmvkxg83QDBXsA_nFXDfTk2E") if err != nil { log.Fatalf("Failed to parse KMS API key: %v", err) } @@ -55,7 +56,7 @@ func ExampleNewClient() { // KMS cluster dynamically expanding it. The added KMS server must not // be part of an exisiting cluster. func ExampleClient_AddNode() { - key, err := kms.ParseAPIKey("k1:d7cY_5k8HbBGkZpoy2hGmvkxg83QDBXsA_nFXDfTk2E") + key, err := mtls.ParsePrivateKey("k1:d7cY_5k8HbBGkZpoy2hGmvkxg83QDBXsA_nFXDfTk2E") if err != nil { log.Fatalf("Failed to parse KMS API key: %v", err) } @@ -85,7 +86,7 @@ func ExampleClient_AddNode() { // ExampleClient_RemoveNode shows how to remove a KMS server from the // cluster it is currently part of. func ExampleClient_RemoveNode() { - key, err := kms.ParseAPIKey("k1:d7cY_5k8HbBGkZpoy2hGmvkxg83QDBXsA_nFXDfTk2E") + key, err := mtls.ParsePrivateKey("k1:d7cY_5k8HbBGkZpoy2hGmvkxg83QDBXsA_nFXDfTk2E") if err != nil { log.Fatalf("Failed to parse KMS API key: %v", err) } @@ -115,7 +116,7 @@ func ExampleClient_RemoveNode() { // ExampleClient_ClusterStatus shows how to fetch cluster status information // from a KMS cluster. func ExampleClient_ClusterStatus() { - key, err := kms.ParseAPIKey("k1:d7cY_5k8HbBGkZpoy2hGmvkxg83QDBXsA_nFXDfTk2E") + key, err := mtls.ParsePrivateKey("k1:d7cY_5k8HbBGkZpoy2hGmvkxg83QDBXsA_nFXDfTk2E") if err != nil { log.Fatalf("Failed to parse KMS API key: %v", err) } @@ -143,7 +144,7 @@ func ExampleClient_ClusterStatus() { // ExampleClient_CreateEnclave shows how to create a new enclave. func ExampleClient_CreateEnclave() { - key, err := kms.ParseAPIKey("k1:d7cY_5k8HbBGkZpoy2hGmvkxg83QDBXsA_nFXDfTk2E") + key, err := mtls.ParsePrivateKey("k1:d7cY_5k8HbBGkZpoy2hGmvkxg83QDBXsA_nFXDfTk2E") if err != nil { log.Fatalf("Failed to parse KMS API key: %v", err) } @@ -172,7 +173,7 @@ func ExampleClient_CreateEnclave() { // ExampleClient_DeleteEnclave shows how to delete an existing enclave. func ExampleClient_DeleteEnclave() { - key, err := kms.ParseAPIKey("k1:d7cY_5k8HbBGkZpoy2hGmvkxg83QDBXsA_nFXDfTk2E") + key, err := mtls.ParsePrivateKey("k1:d7cY_5k8HbBGkZpoy2hGmvkxg83QDBXsA_nFXDfTk2E") if err != nil { log.Fatalf("Failed to parse KMS API key: %v", err) } @@ -202,7 +203,7 @@ func ExampleClient_DeleteEnclave() { // ExampleClient_EnclaveStatus shows how to fetch status information about two enclaves. // Fetching information about multiple enclaves requires just a single network request. func ExampleClient_EnclaveStatus() { - key, err := kms.ParseAPIKey("k1:d7cY_5k8HbBGkZpoy2hGmvkxg83QDBXsA_nFXDfTk2E") + key, err := mtls.ParsePrivateKey("k1:d7cY_5k8HbBGkZpoy2hGmvkxg83QDBXsA_nFXDfTk2E") if err != nil { log.Fatalf("Failed to parse KMS API key: %v", err) } @@ -238,7 +239,7 @@ func ExampleClient_EnclaveStatus() { // ExampleClient_EnclaveStatus shows how to fetch status information about two enclaves. // Fetching information about multiple enclaves requires just a single network request. func ExampleClient_ListEnclaves() { - key, err := kms.ParseAPIKey("k1:d7cY_5k8HbBGkZpoy2hGmvkxg83QDBXsA_nFXDfTk2E") + key, err := mtls.ParsePrivateKey("k1:d7cY_5k8HbBGkZpoy2hGmvkxg83QDBXsA_nFXDfTk2E") if err != nil { log.Fatalf("Failed to parse KMS API key: %v", err) } @@ -270,7 +271,7 @@ func ExampleClient_ListEnclaves() { // ExampleClient_Logs shows how to fetch server log records. func ExampleClient_Logs() { - key, err := kms.ParseAPIKey("k1:d7cY_5k8HbBGkZpoy2hGmvkxg83QDBXsA_nFXDfTk2E") + key, err := mtls.ParsePrivateKey("k1:d7cY_5k8HbBGkZpoy2hGmvkxg83QDBXsA_nFXDfTk2E") if err != nil { log.Fatalf("Failed to parse KMS API key: %v", err) } diff --git a/kms/client.go b/kms/client.go index 7964a59..886bcd9 100644 --- a/kms/client.go +++ b/kms/client.go @@ -22,6 +22,7 @@ import ( "time" "aead.dev/mem" + "aead.dev/mtls" "github.com/minio/kms-go/kms/cmds" "github.com/minio/kms-go/kms/internal/api" "github.com/minio/kms-go/kms/internal/headers" @@ -42,7 +43,7 @@ type Config struct { // // When providing an API key, no TLS.Certificates // or TLS.GetClientCertificate must be present. - APIKey APIKey + APIKey mtls.PrivateKey // Optional TLS configuration. // diff --git a/kms/example_test.go b/kms/example_test.go deleted file mode 100644 index c860bdb..0000000 --- a/kms/example_test.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2023 - MinIO, Inc. All rights reserved. -// Use of this source code is governed by the AGPLv3 -// license that can be found in the LICENSE file. - -package kms_test - -import ( - "fmt" - "log" - - "github.com/minio/kms-go/kms" -) - -func ExampleParseAPIKey() { - key, err := kms.ParseAPIKey("k1:d7cY_5k8HbBGkZpoy2hGmvkxg83QDBXsA_nFXDfTk2E") - if err != nil { - log.Fatal(err) - } - fmt.Println(key) - // Output: - // k1:d7cY_5k8HbBGkZpoy2hGmvkxg83QDBXsA_nFXDfTk2E -} - -func ExampleAPIKey_Identity() { - key, err := kms.ParseAPIKey("k1:d7cY_5k8HbBGkZpoy2hGmvkxg83QDBXsA_nFXDfTk2E") - if err != nil { - log.Fatal(err) - } - fmt.Println(key.Identity()) - // Output: - // h1:Rvxa7nj8zkL48CeDkN6LhpX-K7KK6uhIhpBOcTHNhWw -} diff --git a/kms/go.mod b/kms/go.mod index 651fdc6..75d3759 100644 --- a/kms/go.mod +++ b/kms/go.mod @@ -1,8 +1,9 @@ module github.com/minio/kms-go/kms -go 1.21 +go 1.22.0 require ( aead.dev/mem v0.2.0 + aead.dev/mtls v0.1.0 google.golang.org/protobuf v1.33.0 ) diff --git a/kms/go.sum b/kms/go.sum index 3a478c1..4a94e5a 100644 --- a/kms/go.sum +++ b/kms/go.sum @@ -1,5 +1,7 @@ aead.dev/mem v0.2.0 h1:ufgkESS9+lHV/GUjxgc2ObF43FLZGSemh+W+y27QFMI= aead.dev/mem v0.2.0/go.mod h1:4qj+sh8fjDhlvne9gm/ZaMRIX9EkmDrKOLwmyDtoMWM= +aead.dev/mtls v0.1.0 h1:zT/p8BpBXol0bmRaJz4WyMW3wTjSjJztKlSoXl/a+rs= +aead.dev/mtls v0.1.0/go.mod h1:QirwQiq697/G62Ug6LbzfeR4Nq1vBGch5ajUZdAzJaw= 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= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= diff --git a/kms/identity.go b/kms/identity.go index a11e250..e6ca167 100644 --- a/kms/identity.go +++ b/kms/identity.go @@ -5,55 +5,18 @@ package kms import ( - "crypto" - "crypto/ed25519" "crypto/rand" - "crypto/sha256" "crypto/tls" "crypto/x509" "crypto/x509/pkix" - "encoding/asn1" - "encoding/base64" "encoding/pem" "errors" - "io" "math/big" "strconv" - "strings" "time" -) -// An Identity uniquely identifies a private/public key pair. -// It consists of a prefix for the hash function followed by -// the URL base64-encoded hash of the public key. -// -// For example: -// -// h1:BPbFim5DqUozIYOjcaRAtImU6TdD6W2_chOgxDyCuDw -// -// This package uses the "h1:" prefix for SHA-256 and computes -// the hash of X.509 certificates from the certificate's -// DER-encoded public key info. -// -// For example: -// -// shasum := sha256.Sum256(cert.RawSubjectPublicKeyInfo) -// identity := "h1:" + base64.RawURLEncoding.EncodeToString(shasum[:]) -// -// By verifying the peer's identity, two parties can detect -// MitM¹ attacks during a protocol handshake, like in TLS. -// An identity pins the public key, similar to SSH² or HPKP³. -// -// The empty string represents a pseudo identity and indicates -// that no public key has been provided. -// -// Ref: -// [1] https://en.wikipedia.org/wiki/Man-in-the-middle_attack -// [2] https://en.wikipedia.org/wiki/Key_fingerprint -// [3] https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning -type Identity string - -func (i Identity) String() string { return string(i) } + "aead.dev/mtls" +) // Privilege represents an access control role of identities. // An identity with a higher privilege has access to more APIs. @@ -111,85 +74,12 @@ func (p Privilege) String() string { } } -// An APIKey represents a public/private key pair. -// An API key can be used to authenticate to a TLS server via -// mTLS¹ by generating a X.509 certificate from the API key's -// public key. -// -// Ref: -// [1] https://en.wikipedia.org/wiki/Mutual_authentication#mTLS -type APIKey interface { - // Public returns the API key's public key. - Public() crypto.PublicKey - - // Private returns the API key's private key. - Private() crypto.PrivateKey - - // Identity returns the Identity associated with the - // public key. - Identity() Identity - - // String returns the API key's string representation. - String() string -} - -// GenerateAPIKey generates a new API key using the given -// io.Reader as source of randomness. -// -// If random is nil, the standard library crypto/rand.Reader -// is used. -func GenerateAPIKey(random io.Reader) (APIKey, error) { - pub, priv, err := ed25519.GenerateKey(random) - if err != nil { - return nil, err - } - - id, err := ed25519Identity(pub) - if err != nil { - return nil, err - } - return &apiKey{ - key: priv, - identity: id, - }, nil -} - -// ParseAPIKey parses s as formatted API key. -func ParseAPIKey(s string) (APIKey, error) { - s, found := strings.CutPrefix(s, "k1:") - if !found { - return nil, errors.New("kms: invalid API key type") - } - - if base64.RawURLEncoding.DecodedLen(len(s)) != ed25519.SeedSize { - return nil, errors.New("kms: invalid API key length") - } - - b, err := base64.RawURLEncoding.DecodeString(s) - if err != nil { - return nil, err - } - if len(b) != ed25519.SeedSize { - return nil, errors.New("kms: invalid API key length") - } - - key := ed25519.NewKeyFromSeed(b) - id, err := ed25519Identity(key[ed25519.SeedSize:]) - if err != nil { - return nil, err - } - return &apiKey{ - key: key, - identity: id, - }, nil -} - // GenerateCertificate generates a new self-signed TLS certificate // from the given template using the APIKey's private and public key. // // The template may be nil. In such a case the returned certificate // is generated using a default template and valid for 90 days. -func GenerateCertificate(key APIKey, template *x509.Certificate) (tls.Certificate, error) { +func GenerateCertificate(key mtls.PrivateKey, template *x509.Certificate) (tls.Certificate, error) { if template == nil { serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) @@ -232,41 +122,3 @@ func GenerateCertificate(key APIKey, template *x509.Certificate) (tls.Certificat } return cert, nil } - -// apiKey is an APIKey implementation using Ed25519 public/private keys. -type apiKey struct { - key ed25519.PrivateKey - identity Identity -} - -func (ak *apiKey) Public() crypto.PublicKey { return ak.key.Public() } - -func (ak *apiKey) Private() crypto.PrivateKey { - private := make([]byte, 0, len(ak.key)) - return ed25519.PrivateKey(append(private, ak.key...)) -} - -func (ak *apiKey) Identity() Identity { return ak.identity } - -func (ak *apiKey) String() string { - return "k1:" + base64.RawURLEncoding.EncodeToString(ak.key[:ed25519.SeedSize]) -} - -func ed25519Identity(pubKey []byte) (Identity, error) { - type publicKeyInfo struct { - Algorithm pkix.AlgorithmIdentifier - PublicKey asn1.BitString - } - - derPublicKey, err := asn1.Marshal(publicKeyInfo{ - Algorithm: pkix.AlgorithmIdentifier{ - Algorithm: asn1.ObjectIdentifier{1, 3, 101, 112}, - }, - PublicKey: asn1.BitString{BitLength: len(pubKey) * 8, Bytes: pubKey}, - }) - if err != nil { - return "", err - } - id := sha256.Sum256(derPublicKey) - return "h1:" + Identity(base64.RawURLEncoding.EncodeToString(id[:])), nil -} diff --git a/kms/log.go b/kms/log.go index 392850d..afc15ba 100644 --- a/kms/log.go +++ b/kms/log.go @@ -12,6 +12,7 @@ import ( "net/netip" "time" + "aead.dev/mtls" pb "github.com/minio/kms-go/kms/protobuf" ) @@ -58,7 +59,7 @@ type LogRecord struct { // If non-empty, identity of the request that caused // this event. - Identity Identity + Identity mtls.Identity // If valid, IP address of the client sending the // request that caused this event. @@ -81,7 +82,7 @@ func (r *LogRecord) MarshalPB(v *pb.LogRecord) error { }) } } - if r.Method != "" || r.Path != "" || r.Identity != "" || r.IP.IsValid() { + if r.Method != "" || r.Path != "" || r.Identity != (mtls.Identity{}) || r.IP.IsValid() { v.Req = &pb.LogRecord_Request{ Method: r.Method, Path: r.Path, @@ -94,13 +95,22 @@ func (r *LogRecord) MarshalPB(v *pb.LogRecord) error { // UnmarshalPB initializes the LogRecord from its protobuf representation. func (r *LogRecord) UnmarshalPB(v *pb.LogRecord) error { - var ip netip.Addr + var ( + ip netip.Addr + id mtls.Identity + ) if v.Req != nil { var err error if ip, err = netip.ParseAddr(v.Req.IP); err != nil { return err } } + if v.Req.Identity != "" { + var err error + if id, err = mtls.ParseIdentity(v.Req.Identity); err != nil { + return err + } + } r.Level = slog.Level(v.Level) r.Message = v.Message @@ -117,7 +127,7 @@ func (r *LogRecord) UnmarshalPB(v *pb.LogRecord) error { r.Method = v.Req.GetMethod() r.Path = v.Req.GetPath() - r.Identity = Identity(v.Req.GetIdentity()) + r.Identity = id r.IP = ip return nil } diff --git a/kms/request.go b/kms/request.go index edd62ce..9223fc3 100644 --- a/kms/request.go +++ b/kms/request.go @@ -11,6 +11,7 @@ import ( "net/netip" "time" + "aead.dev/mtls" "github.com/minio/kms-go/kms/cmds" pb "github.com/minio/kms-go/kms/protobuf" ) @@ -292,7 +293,7 @@ type LogRequest struct { Path string // The servers sends only log records with this identity. - Identity Identity + Identity mtls.Identity // The server sends only log records with this IP address. IP netip.Addr @@ -321,20 +322,29 @@ func (r *LogRequest) MarshalPB(v *pb.LogRequest) error { // UnmarshalPB initializes the LogRequest from its protobuf representation. func (r *LogRequest) UnmarshalPB(v *pb.LogRequest) error { - var ip netip.Addr + var ( + ip netip.Addr + id mtls.Identity + ) if v.IP != "" { var err error if ip, err = netip.ParseAddr(v.IP); err != nil { return err } } + if v.Identity != "" { + var err error + if id, err = mtls.ParseIdentity(v.Identity); err != nil { + return err + } + } r.Level = slog.Level(v.Level) r.Message = v.Message r.Since = v.Since.AsTime() r.Method = v.Method r.Path = v.Path - r.Identity = Identity(v.Identity) + r.Identity = id r.IP = ip r.TraceLevel = slog.Level(v.TraceLevel) return nil @@ -745,12 +755,12 @@ type AssignPolicyRequest struct { Policy string // Identity is the identity to which the policy should apply. - Identity Identity + Identity mtls.Identity } // MarshalPB converts the AssignPolicyRequest into its protobuf representation. func (r *AssignPolicyRequest) MarshalPB(v *pb.AssignPolicyRequest) error { - if r.Identity == "" { + if r.Identity == (mtls.Identity{}) { return errors.New("kms: identity is empty") } @@ -764,8 +774,12 @@ func (r *AssignPolicyRequest) UnmarshalPB(v *pb.AssignPolicyRequest) error { if v.Identity == "" { return errors.New("kms: identity is empty") } + id, err := mtls.ParseIdentity(v.Identity) + if err != nil { + return err + } - r.Identity = Identity(v.Identity) + r.Identity = id r.Policy = v.Policy return nil } @@ -810,7 +824,7 @@ func (r *DeletePolicyRequest) UnmarshalPB(v *pb.DeletePolicyRequest) error { // CreateIdentityRequest contains options for creating new identities. type CreateIdentityRequest struct { // Identity is the identity that is created. - Identity Identity + Identity mtls.Identity // Privilege is the identity's privilege. If empty, defaults to User. Privilege Privilege @@ -835,15 +849,24 @@ func (r *CreateIdentityRequest) MarshalPB(v *pb.CreateIdentityRequest) error { // UnmarshalPB initializes the CreateIdentityRequest from its protobuf representation. func (r *CreateIdentityRequest) UnmarshalPB(v *pb.CreateIdentityRequest) error { - var privilege Privilege + var ( + privilege Privilege + id mtls.Identity + ) if v.Privilege != "" { var err error if privilege, err = ParsePrivilege(v.Privilege); err != nil { return err } } + if v.Identity != "" { + var err error + if id, err = mtls.ParseIdentity(v.Identity); err != nil { + return err + } + } - r.Identity = Identity(v.Identity) + r.Identity = id r.Privilege = privilege r.IsServiceAccount = v.IsServiceAccount return nil @@ -852,7 +875,7 @@ func (r *CreateIdentityRequest) UnmarshalPB(v *pb.CreateIdentityRequest) error { // IdentityRequest contains options for fetching identity metadata. type IdentityRequest struct { // Identity is the identity. - Identity Identity + Identity mtls.Identity } // MarshalPB converts the IdentityRequest into its protobuf representation. @@ -863,14 +886,22 @@ func (r *IdentityRequest) MarshalPB(v *pb.IdentityRequest) error { // UnmarshalPB initializes the IdentityRequest from its protobuf representation. func (r *IdentityRequest) UnmarshalPB(v *pb.IdentityRequest) error { - r.Identity = Identity(v.Identity) + var id mtls.Identity + if v.Identity != "" { + var err error + if id, err = mtls.ParseIdentity(v.Identity); err != nil { + return err + } + } + + r.Identity = id return nil } // DeleteIdentityRequest contains options for deleting an identity. type DeleteIdentityRequest struct { // Identity is the identity that is deleted. - Identity Identity + Identity mtls.Identity } // MarshalPB converts the DeleteIdentityRequest into its protobuf representation. @@ -881,6 +912,11 @@ func (r *DeleteIdentityRequest) MarshalPB(v *pb.DeleteIdentityRequest) error { // UnmarshalPB initializes the DeleteIdentityRequest from its protobuf representation. func (r *DeleteIdentityRequest) UnmarshalPB(v *pb.DeleteIdentityRequest) error { - r.Identity = Identity(v.Identity) + id, err := mtls.ParseIdentity(v.Identity) + if err != nil { + return err + } + + r.Identity = id return nil } diff --git a/kms/response.go b/kms/response.go index 41fd586..7d0fb64 100644 --- a/kms/response.go +++ b/kms/response.go @@ -11,6 +11,7 @@ import ( "net/http" "time" + "aead.dev/mtls" "github.com/minio/kms-go/kms/cmds" "github.com/minio/kms-go/kms/internal/headers" "github.com/minio/kms-go/kms/internal/pool" @@ -516,7 +517,7 @@ type EnclaveStatusResponse struct { CreatedAt time.Time // CreatedBy is the identity that created the enclave. - CreatedBy Identity + CreatedBy mtls.Identity } // MarshalPB converts the EnclaveStatusResponse into its protobuf representation. @@ -529,9 +530,17 @@ func (r *EnclaveStatusResponse) MarshalPB(v *pb.EnclaveStatusResponse) error { // UnmarshalPB initializes the EnclaveStatusResponse from its protobuf representation. func (r *EnclaveStatusResponse) UnmarshalPB(v *pb.EnclaveStatusResponse) error { + var id mtls.Identity + if v.CreatedBy != "" { + var err error + if id, err = mtls.ParseIdentity(v.CreatedBy); err != nil { + return err + } + } + r.Name = v.Name r.CreatedAt = v.CreatedAt.AsTime() - r.CreatedBy = Identity(v.CreatedBy) + r.CreatedBy = id return nil } @@ -550,7 +559,7 @@ type KeyStatusResponse struct { CreatedAt time.Time // CreatedBy is the identity that created this key version. - CreatedBy Identity + CreatedBy mtls.Identity } // MarshalPB converts the KeyStatusResponse into its protobuf representation. @@ -565,16 +574,20 @@ func (r *KeyStatusResponse) MarshalPB(v *pb.KeyStatusResponse) error { // UnmarshalPB initializes the KeyStatusResponse from its protobuf representation. func (r *KeyStatusResponse) UnmarshalPB(v *pb.KeyStatusResponse) error { + var id mtls.Identity t, err := ParseSecretKeyType(v.Type) if err != nil { return err } + if id, err = mtls.ParseIdentity(v.CreatedBy); err != nil { + return err + } r.Name = v.Name r.Type = t r.Version = int(v.Version) r.CreatedAt = v.CreatedAt.AsTime() - r.CreatedBy = Identity(v.CreatedBy) + r.CreatedBy = id return nil } @@ -664,7 +677,7 @@ type PolicyStatusResponse struct { CreatedAt time.Time // CreatedBy is the identity that created the policy. - CreatedBy Identity + CreatedBy mtls.Identity } // MarshalPB converts the PolicyStatusResponse into its protobuf representation. @@ -677,9 +690,17 @@ func (r *PolicyStatusResponse) MarshalPB(v *pb.PolicyStatusResponse) error { // UnmarshalPB initializes the PolicyStatusResponse from its protobuf representation. func (r *PolicyStatusResponse) UnmarshalPB(v *pb.PolicyStatusResponse) error { + var id mtls.Identity + if v.CreatedBy != "" { + var err error + if id, err = mtls.ParseIdentity(v.CreatedBy); err != nil { + return err + } + } + r.Name = v.Name r.CreatedAt = v.CreatedAt.AsTime() - r.CreatedBy = Identity(v.CreatedBy) + r.CreatedBy = id return nil } @@ -698,7 +719,7 @@ type PolicyResponse struct { CreatedAt time.Time // CreatedBy is the identity that created the policy. - CreatedBy Identity + CreatedBy mtls.Identity } // MarshalPB converts the PolicyResponse into its protobuf representation. @@ -730,9 +751,15 @@ func (r *PolicyResponse) MarshalPB(v *pb.PolicyResponse) error { // UnmarshalPB initializes the PolicyResponse from its protobuf representation. func (r *PolicyResponse) UnmarshalPB(v *pb.PolicyResponse) error { - r.Name = v.Name + var id mtls.Identity + if v.CreatedBy != "" { + var err error + if id, err = mtls.ParseIdentity(v.CreatedBy); err != nil { + return err + } + } - r.Allow = make(map[cmds.Command]RuleSet, len(v.Allow)) + allow := make(map[cmds.Command]RuleSet, len(v.Allow)) for cmd, set := range v.Allow { var c cmds.Command if err := c.UnmarshalText([]byte(cmd)); err != nil { @@ -743,10 +770,10 @@ func (r *PolicyResponse) UnmarshalPB(v *pb.PolicyResponse) error { if err := rs.UnmarshalPB(set); err != nil { return err } - r.Allow[c] = rs + allow[c] = rs } - r.Deny = make(map[cmds.Command]RuleSet, len(v.Deny)) + deny := make(map[cmds.Command]RuleSet, len(v.Deny)) for cmd, set := range v.Deny { var c cmds.Command if err := c.UnmarshalText([]byte(cmd)); err != nil { @@ -757,18 +784,21 @@ func (r *PolicyResponse) UnmarshalPB(v *pb.PolicyResponse) error { if err := rs.UnmarshalPB(set); err != nil { return err } - r.Deny[c] = rs + deny[c] = rs } + r.Name = v.Name + r.Allow = allow + r.Deny = deny r.CreatedAt = v.CreatedAt.AsTime() - r.CreatedBy = Identity(v.CreatedBy) + r.CreatedBy = id return nil } // IdentityResponse contains information about an identity. type IdentityResponse struct { // Identity is the identity referring to a private/public key pair. - Identity Identity + Identity mtls.Identity // Privilege is the identity's privilege. Privilege Privilege @@ -781,7 +811,7 @@ type IdentityResponse struct { CreatedAt time.Time // CreatedBy is the identity that created this identity. - CreatedBy Identity + CreatedBy mtls.Identity // IsServiceAccount indicates whether this identity is a service // account. By default, service accounts inherit the permissions @@ -790,7 +820,7 @@ type IdentityResponse struct { IsServiceAccount bool // ServiceAccounts contains all service accounts of this identity. - ServiceAccounts []Identity + ServiceAccounts []mtls.Identity } // MarshalPB converts the IdentityResponse into its protobuf representation. @@ -810,15 +840,38 @@ func (r *IdentityResponse) MarshalPB(v *pb.IdentityResponse) error { // UnmarshalPB initializes the IdentityResponse from its protobuf representation. func (r *IdentityResponse) UnmarshalPB(v *pb.IdentityResponse) error { - r.Identity = Identity(v.Identity) + var ( + err error + id, createdBy mtls.Identity + serviceAccounts []mtls.Identity + ) + if v.Identity != "" { + if id, err = mtls.ParseIdentity(v.Identity); err != nil { + return err + } + } + if v.CreatedBy != "" { + if createdBy, err = mtls.ParseIdentity(v.CreatedBy); err != nil { + return err + } + } + if len(v.ServiceAccounts) > 0 { + serviceAccounts = make([]mtls.Identity, 0, len(v.ServiceAccounts)) + for _, a := range v.ServiceAccounts { + i, err := mtls.ParseIdentity(a) + if err != nil { + return err + } + serviceAccounts = append(serviceAccounts, i) + } + } + + r.Identity = id r.Privilege = Privilege(v.Privilege) r.Policy = v.Policy r.CreatedAt = v.CreatedAt.AsTime() - r.CreatedBy = Identity(v.CreatedBy) + r.CreatedBy = createdBy r.IsServiceAccount = v.IsServiceAccount - r.ServiceAccounts = make([]Identity, 0, len(v.ServiceAccounts)) - for _, a := range v.ServiceAccounts { - r.ServiceAccounts = append(r.ServiceAccounts, Identity(a)) - } + r.ServiceAccounts = serviceAccounts return nil }