Skip to content

Commit

Permalink
Added lastRotated to cmk details and added unit tests (#196)
Browse files Browse the repository at this point in the history
  • Loading branch information
arishta-yb authored Nov 7, 2023
1 parent 19dc7b8 commit 87c361a
Show file tree
Hide file tree
Showing 10 changed files with 428 additions and 45 deletions.
2 changes: 1 addition & 1 deletion cmd/cluster/encryption/encryption.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ var listCmk = &cobra.Command{
Output: os.Stdout,
Format: formatter.NewCMKFormat(viper.GetString("output")),
}
formatter.CMKWrite(cmkCtx, *resp.GetData().Spec.Get())
formatter.CMKWrite(cmkCtx, *resp.Data)
},
}

Expand Down
6 changes: 3 additions & 3 deletions cmd/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ stunning-sole Dedicated 2.16.0.1-b7 ACTIVE 💚 AWS us-we
Expect(err).ToNot(HaveOccurred())
err = loadJson("./test/fixtures/nodes.json", &responseNodes)
Expect(err).ToNot(HaveOccurred())
err = loadJson("./test/fixtures/cmk.json", &responseCMK)
err = loadJson("./test/fixtures/aws_cmk.json", &responseCMK)
Expect(err).ToNot(HaveOccurred())
err = loadJson("./test/fixtures/one-cluster.json", &responseCluster)
Expect(err).ToNot(HaveOccurred())
Expand Down Expand Up @@ -273,8 +273,8 @@ device-ip-gween device-ip-gween 152.165.26.42/32
Encryption at Rest
Provider Key Alias Security Principals CMK Status
AWS 0a80e409-e890-42fc-b209-bafb69931b2c arn:aws:kms:us-east-1:745846189716:key/db373c8d-1592-4c73-bfa3-420d05922933 ACTIVE
Provider Key Alias Last Rotated Security Principals CMK Status
AWS 0a80e409-e690-42fc-b209-baf969930b2c 2023-11-03T07:37:26.351Z arn:aws:kms:us-east-1:745846189716:key/41c64d5g-c97d-472c-889e-0d9f80d2c754 ACTIVE
Nodes
Expand Down
300 changes: 300 additions & 0 deletions cmd/encryption_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
package cmd_test

import (
"fmt"
"net/http"
"os"
"os/exec"
"strings"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gbytes"
"github.com/onsi/gomega/gexec"
"github.com/onsi/gomega/ghttp"
openapi "github.com/yugabyte/yugabytedb-managed-go-client-internal"
)

var _ = Describe("Customer Managed Keys Test", func() {

var (
server *ghttp.Server
statusCode int
args []string
responseAccount openapi.AccountListResponse
responseProject openapi.AccountListResponse
responseListCluster openapi.ClusterListResponse
responseCMK openapi.CMKResponse
)

BeforeEach(func() {
args = os.Args
os.Args = []string{}
var err error
server, err = newGhttpServer(responseAccount, responseProject)
Expect(err).ToNot(HaveOccurred())
os.Setenv("YBM_HOST", fmt.Sprintf("http://%s", server.Addr()))
os.Setenv("YBM_APIKEY", "test-token")

statusCode = 200
err = loadJson("./test/fixtures/list-clusters.json", &responseListCluster)
Expect(err).ToNot(HaveOccurred())
server.AppendHandlers(
ghttp.CombineHandlers(
ghttp.VerifyRequest(http.MethodGet, "/api/public/v1/accounts/340af43a-8a7c-4659-9258-4876fd6a207b/projects/78d4459c-0f45-47a5-899a-45ddf43eba6e/clusters"),
ghttp.RespondWithJSONEncodedPtr(&statusCode, responseListCluster),
),
)
})

var _ = Describe("Describe Cluster CMK", func() {

testCases := []struct {
jsonFilePath string
provider string
expected string
}{
{
jsonFilePath: "./test/fixtures/aws_cmk.json",
provider: "AWS",
expected: `Provider Key Alias Last Rotated Security Principals CMK Status
AWS 0a80e409-e690-42fc-b209-baf969930b2c 2023-11-03T07:37:26.351Z arn:aws:kms:us-east-1:745846189716:key/41c64d5g-c97d-472c-889e-0d9f80d2c754 ACTIVE` + "\n",
},
{
jsonFilePath: "./test/fixtures/azure_cmk.json",
provider: "AZURE",
expected: `Provider Key Alias Last Rotated Security Principals CMK Status
AZURE 8aXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX5b 2023-11-03T07:37:26.351Z https://test-azure-gj.vault.azure.net/ ACTIVE` + "\n",
},
{
jsonFilePath: "./test/fixtures/gcp_cmk.json",
provider: "GCP",
expected: `Provider Key Alias Last Rotated Security Principals CMK Status
GCP GCP-test-key 2023-11-03T07:37:26.351Z projects/<your-project-id>/locations/global/keyRings/GCP-test-key-ring/cryptoKeys/GCP-test-key ACTIVE` + "\n",
},
}

for _, tc := range testCases {
tc := tc
It(fmt.Sprintf("should successfully get CMK details for %s", tc.provider), func() {
err := loadJson(tc.jsonFilePath, &responseCMK)
Expect(err).ToNot(HaveOccurred())
server.AppendHandlers(
ghttp.CombineHandlers(
ghttp.VerifyRequest(http.MethodGet, "/api/public/v1/accounts/340af43a-8a7c-4659-9258-4876fd6a207b/projects/78d4459c-0f45-47a5-899a-45ddf43eba6e/clusters/5f80730f-ba3f-4f7e-8c01-f8fa4c90dad8/cmks"),
ghttp.RespondWithJSONEncodedPtr(&statusCode, responseCMK),
),
)
cmd := exec.Command(compiledCLIPath, "cluster", "encryption", "list", "--cluster-name", "stunning-sole")
session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
Expect(err).NotTo(HaveOccurred())
session.Wait(2)
o := string(session.Out.Contents()[:])
Expect(o).Should(Equal(tc.expected))
session.Kill()
})
}

It("should fail if no EAR configuration found for the cluster", func() {
responseCMK = *openapi.NewCMKResponse()
server.AppendHandlers(
ghttp.CombineHandlers(
ghttp.VerifyRequest(http.MethodGet, "/api/public/v1/accounts/340af43a-8a7c-4659-9258-4876fd6a207b/projects/78d4459c-0f45-47a5-899a-45ddf43eba6e/clusters/5f80730f-ba3f-4f7e-8c01-f8fa4c90dad8/cmks"),
ghttp.RespondWithJSONEncodedPtr(&statusCode, responseCMK),
),
)
cmd := exec.Command(compiledCLIPath, "cluster", "encryption", "list", "--cluster-name", "stunning-sole")
session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
Expect(err).NotTo(HaveOccurred())
session.Wait(2)
Expect(session.Err).Should(gbytes.Say("No Encryption at rest configuration found for this cluster"))
session.Kill()
})
})

var _ = Describe("Update cluster CMK", func() {

testCases := []struct {
cloudProvider string
spec string
}{
{
cloudProvider: "AWS",
spec: "cloud-provider=AWS,aws-secret-key=<your-secret-key>,aws-access-key=<your-access-key>",
},
{
cloudProvider: "AZURE",
spec: "cloud-provider=AZURE,azu-client-id=<your-client-id>,azu-client-secret=<your-client-secret>,azu-tenant-id=<your-tenant-id>,azu-key-name=<your-key-name>,azu-key-vault-uri=<your-key-vault-uri>",
},
{
cloudProvider: "GCP",
spec: "cloud-provider=GCP,gcp-resource-id=projects/<your-project>/locations/<your-location>/keyRings/<your-key-ring-name>/cryptoKeys/<your-key-name>,gcp-service-account-path=creds.json",
},
}

BeforeEach(func() {
fileName := "creds.json"
os.WriteFile(fileName, []byte("{}"), 0644)
})

AfterEach(func() {
os.Remove("creds.json")
})

for _, tc := range testCases {
tc := tc

It(fmt.Sprintf("should successfully update CMK for %s", tc.cloudProvider), func() {
err := loadJson(fmt.Sprintf("./test/fixtures/%s_cmk.json", strings.ToLower(tc.cloudProvider)), &responseCMK)
Expect(err).ToNot(HaveOccurred())
server.AppendHandlers(
ghttp.CombineHandlers(
ghttp.VerifyRequest(http.MethodPut, "/api/public/v1/accounts/340af43a-8a7c-4659-9258-4876fd6a207b/projects/78d4459c-0f45-47a5-899a-45ddf43eba6e/clusters/5f80730f-ba3f-4f7e-8c01-f8fa4c90dad8/cmks"),
ghttp.RespondWithJSONEncodedPtr(&statusCode, responseCMK),
),
)
cmd := exec.Command(compiledCLIPath, "cluster", "encryption", "update", "--cluster-name", "stunning-sole", "--encryption-spec", tc.spec)
session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
Expect(err).NotTo(HaveOccurred())
session.Wait(2)
Expect(session.Out).Should(gbytes.Say("Successfully updated encryption spec for cluster stunning-sole"))
session.Kill()
})
}

It("should fail if invalid cloud provider in encryption spec", func() {
cmd := exec.Command(compiledCLIPath, "cluster", "encryption", "update", "--cluster-name", "stunning-sole", "--encryption-spec", "cloud-provider=TEST_PROVIDER,access-key=<your-access-key>,secret-key=<your-secret-key>")
session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
Expect(err).NotTo(HaveOccurred())
session.Wait(2)
Expect(session.Err).Should(gbytes.Say("Incorrect format in CMK spec: invalid cloud-provider"))
session.Kill()
})

It("should fail if missing parameters in encryption spec", func() {
cmd := exec.Command(compiledCLIPath, "cluster", "encryption", "update", "--cluster-name", "stunning-sole", "--encryption-spec", "cloud-provider=AWS,aws-access-key=<your-access-key>,secret-key=<your-secret-key>")
session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
Expect(err).NotTo(HaveOccurred())
session.Wait(2)
Expect(session.Err).Should(gbytes.Say("Could not read AWS Secret key:"))
session.Kill()
})

It("should succeed if no EAR configuration found for the cluster", func() {
// In this case, a new EAR configuration would be added to this cluster
responseCMK = *openapi.NewCMKResponse()
server.AppendHandlers(
ghttp.CombineHandlers(
ghttp.VerifyRequest(http.MethodPut, "/api/public/v1/accounts/340af43a-8a7c-4659-9258-4876fd6a207b/projects/78d4459c-0f45-47a5-899a-45ddf43eba6e/clusters/5f80730f-ba3f-4f7e-8c01-f8fa4c90dad8/cmks"),
ghttp.RespondWithJSONEncodedPtr(&statusCode, responseCMK),
),
)
cmd := exec.Command(compiledCLIPath, "cluster", "encryption", "update", "--cluster-name", "stunning-sole", "--encryption-spec", "cloud-provider=AWS,aws-secret-key=<your-secret-key>,aws-access-key=<your-access-key>")
session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
Expect(err).NotTo(HaveOccurred())
session.Wait(2)
Expect(session.Out).Should(gbytes.Say("Successfully updated encryption spec for cluster stunning-sole"))
session.Kill()
})
})

var _ = Describe("Update cluster CMK state", func() {

testCases := []struct {
action string
expected string
}{
{
action: "--enable",
expected: "Successfully ENABLED encryption spec status for cluster stunning-sole",
},
{
action: "--disable",
expected: "Successfully DISABLED encryption spec status for cluster stunning-sole",
},
}

for _, tc := range testCases {
tc := tc

It(fmt.Sprintf("should successfully %s the CMK state for azure", tc.action), func() {

err := loadJson("./test/fixtures/aws_cmk.json", &responseCMK)
Expect(err).ToNot(HaveOccurred())
server.AppendHandlers(
ghttp.CombineHandlers(
ghttp.VerifyRequest(http.MethodGet, "/api/public/v1/accounts/340af43a-8a7c-4659-9258-4876fd6a207b/projects/78d4459c-0f45-47a5-899a-45ddf43eba6e/clusters/5f80730f-ba3f-4f7e-8c01-f8fa4c90dad8/cmks"),
ghttp.RespondWithJSONEncodedPtr(&statusCode, responseCMK),
),
ghttp.CombineHandlers(
ghttp.VerifyRequest(http.MethodPut, "/api/public/v1/accounts/340af43a-8a7c-4659-9258-4876fd6a207b/projects/78d4459c-0f45-47a5-899a-45ddf43eba6e/clusters/5f80730f-ba3f-4f7e-8c01-f8fa4c90dad8/cmks/41c64d5g-c97d-472c-889e-0d9f80d2c754/state"),
ghttp.RespondWithJSONEncodedPtr(&statusCode, responseCMK),
),
)

cmd := exec.Command(compiledCLIPath, "cluster", "encryption", "update-state", "--cluster-name", "stunning-sole", tc.action)
session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
Expect(err).NotTo(HaveOccurred())
session.Wait(2)
Expect(session.Out).Should(gbytes.Say(tc.expected))
session.Kill()
})
}

It("should fail if no or both flags are specified", func() {
err := loadJson("./test/fixtures/aws_cmk.json", &responseCMK)
Expect(err).ToNot(HaveOccurred())
server.AppendHandlers(
ghttp.CombineHandlers(
ghttp.VerifyRequest(http.MethodGet, "/api/public/v1/accounts/340af43a-8a7c-4659-9258-4876fd6a207b/projects/78d4459c-0f45-47a5-899a-45ddf43eba6e/clusters/5f80730f-ba3f-4f7e-8c01-f8fa4c90dad8/cmks"),
ghttp.RespondWithJSONEncodedPtr(&statusCode, responseCMK),
),
)
cmd := exec.Command(compiledCLIPath, "cluster", "encryption", "update-state", "--cluster-name", "stunning-sole")
session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
Expect(err).NotTo(HaveOccurred())
session.Wait(2)
Expect(session.Err).Should(gbytes.Say("Please enter valid input. Specify either enable or disable flag."))

session.Kill()
})

It("should fail if both flags are specified", func() {
err := loadJson("./test/fixtures/aws_cmk.json", &responseCMK)
Expect(err).ToNot(HaveOccurred())
server.AppendHandlers(
ghttp.CombineHandlers(
ghttp.VerifyRequest(http.MethodGet, "/api/public/v1/accounts/340af43a-8a7c-4659-9258-4876fd6a207b/projects/78d4459c-0f45-47a5-899a-45ddf43eba6e/clusters/5f80730f-ba3f-4f7e-8c01-f8fa4c90dad8/cmks"),
ghttp.RespondWithJSONEncodedPtr(&statusCode, responseCMK),
),
)
cmd := exec.Command(compiledCLIPath, "cluster", "encryption", "update-state", "--cluster-name", "stunning-sole", "--enable", "--disable")
session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
Expect(err).NotTo(HaveOccurred())
session.Wait(2)
Expect(session.Err).Should(gbytes.Say("Please enter valid input. Specify either enable or disable flag."))
session.Kill()
})

It("should fail if no EAR configuration found for the cluster", func() {
responseCMK = *openapi.NewCMKResponse()
server.AppendHandlers(
ghttp.CombineHandlers(
ghttp.VerifyRequest(http.MethodGet, "/api/public/v1/accounts/340af43a-8a7c-4659-9258-4876fd6a207b/projects/78d4459c-0f45-47a5-899a-45ddf43eba6e/clusters/5f80730f-ba3f-4f7e-8c01-f8fa4c90dad8/cmks"),
ghttp.RespondWithJSONEncodedPtr(&statusCode, responseCMK),
),
)
cmd := exec.Command(compiledCLIPath, "cluster", "encryption", "update-state", "--cluster-name", "stunning-sole", "--enable")
session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
Expect(err).NotTo(HaveOccurred())
session.Wait(2)
Expect(session.Err).Should(gbytes.Say("No Encryption at rest configuration found for this cluster"))
session.Kill()
})
})

AfterEach(func() {
os.Args = args
server.Close()
})
})
27 changes: 27 additions & 0 deletions cmd/test/fixtures/aws_cmk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"data": {
"spec": {
"provider_type": "AWS",
"aws_cmk_spec": {
"access_key": "AKXXXXXXXXXXXXXXXXGC",
"secret_key": "l/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXOo",
"arn_list": [
"arn:aws:kms:us-east-1:745846189716:key/41c64d5g-c97d-472c-889e-0d9f80d2c754"
],
"alias_name": "0a80e409-e690-42fc-b209-baf969930b2c"
},
"status": "ACTIVE",
"gcp_cmk_spec": null,
"azure_cmk_spec": null,
"is_enabled": false
},
"info": {
"cmk_id": "41c64d5g-c97d-472c-889e-0d9f80d2c754",
"rotated_on": "2023-11-03T07:37:26.351Z",
"metadata": {
"created_on": "2023-11-03T07:37:26.351Z",
"updated_on": "2023-11-03T07:38:30.141Z"
}
}
}
}
28 changes: 28 additions & 0 deletions cmd/test/fixtures/azure_cmk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"data": {
"spec": {
"provider_type": "AZURE",
"aws_cmk_spec": null,
"status": "ACTIVE",
"gcp_cmk_spec": null,
"azure_cmk_spec": {
"client_id": "8aXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX5b",
"client_secret": "bfXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXlZ",
"tenant_id": "81XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX83",
"key_vault_uri": "https://test-azure-gj.vault.azure.net/",
"key_name": "AZURE-test-key",
"key_algorithm": "RSA",
"key_size": 2048
},
"is_enabled": true
},
"info": {
"cmk_id": "41c64d5f-c97d-472c-889e-0d9f80d2c754",
"rotated_on": "2023-11-03T07:37:26.351Z",
"metadata": {
"created_on": "2023-11-03T07:37:26.351Z",
"updated_on": "2023-11-03T07:38:30.141Z"
}
}
}
}
Loading

0 comments on commit 87c361a

Please sign in to comment.