diff --git a/internal/cli/atlas/logs/logs.go b/internal/cli/atlas/logs/logs.go index d37c7e3a79..5b7a998d12 100644 --- a/internal/cli/atlas/logs/logs.go +++ b/internal/cli/atlas/logs/logs.go @@ -29,11 +29,9 @@ func Builder() *cobra.Command { Short: "Download host logs for your project.", } - keyProvidersCmd := decryption.KeyProvidersBuilder() - keyProvidersCmd.Hidden = true cmd.AddCommand( DownloadBuilder(), - keyProvidersCmd, + decryption.KeyProvidersBuilder(), DecryptBuilder(), ) diff --git a/internal/cli/decryption/key_providers.go b/internal/cli/decryption/key_providers.go index 57fbc91ee9..d8012247c1 100644 --- a/internal/cli/decryption/key_providers.go +++ b/internal/cli/decryption/key_providers.go @@ -24,6 +24,7 @@ func KeyProvidersBuilder() *cobra.Command { Use: "keyProviders", Aliases: cli.GenerateAliases("keyProviders", "keys"), Short: "Manage your key collections.", + Hidden: true, } cmd.AddCommand(KeyProvidersListBuilder()) diff --git a/internal/cli/decryption/list_key_provider_test.go b/internal/cli/decryption/list_key_provider_test.go index 94bbaa4c28..ac7d33b13c 100644 --- a/internal/cli/decryption/list_key_provider_test.go +++ b/internal/cli/decryption/list_key_provider_test.go @@ -17,12 +17,10 @@ package decryption import ( - "bytes" "testing" "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/flag" "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/test" - "github.com/spf13/afero" ) func TestListKeyProviderBuilder(t *testing.T) { @@ -36,29 +34,3 @@ func TestListKeyProviderBuilder(t *testing.T) { }, ) } - -func TestKeyProviderListOpts_Run(t *testing.T) { - fileJSON := []byte(`{"ts":{"$date":{"$numberLong":"1644232049921"}},"version":"0.0","compressionMode":"zstd","keyStoreIdentifier":{"provider":"local","filename":"localKey"},"encryptedKey":{"$binary":{"base64":"+yjPCaKKE1M8fZmPGzGHkyfHYxaw34okpavsHzpd8iPVx2+JjOhXwXw5E2FdI5Rcb5JgmcPUFRPISh/7Si1R/g==","subType":"0"}},"MAC":"qE9fUsGK0EuRrrCRAQAAAAAAAAAAAAAA","auditRecordType":"header"} -{"ts":{"$date":{"$numberLong":"1644232049922"}},"log":"1Lu4o8XVMM/Rg7GKAQAAAAEAAAAAAAAA/8tXQ36mEd90OaAOzCOSti7N5a2jr0B9ek48/uvyteG/zUJHyM16Hs3wMEhDqTQGBwGhWSHEqXh0/5Jbz6tXsYHhDTMr1BOsn1zaavZScx/CkO5+Hd8Vx+zeFPREtQTe1y+JngXSIroezeyV0/zF4YC4vpug+OZtrEQLNEgwT2bjaqUyaKDbmzCNetd2Ff/eFfMFzinbzKVgXAC7T4YmDuowqXommEXLIBiYh2u4VagwJKZRw5OGZjnvqwyVpSPgGqLxGKUoFigh3NgC6EuGi17VIs5BLRZOIw7+OfbPgQQiKzjCxCk="} -{"ts":{"$date":{"$numberLong":"1644232049921"}},"version":"0.0","compressionMode":"zstd","keyStoreIdentifier":{"provider":"kmip","uid":"uniqueKeyID","kmipServerName":["kmipServerName"],"kmipPort":{"$numberInt":"8081"},"keyWrapMethod":"get"},"encryptedKey":{"$binary":{"base64":"+yjPCaKKE1M8fZmPGzGHkyfHYxaw34okpavsHzpd8iPVx2+JjOhXwXw5E2FdI5Rcb5JgmcPUFRPISh/7Si1R/g==","subType":"0"}},"MAC":"qE9fUsGK0EuRrrCRAQAAAAAAAAAAAAAA","auditRecordType":"header"} -{"ts":{"$date":{"$numberLong":"1644232049922"}},"log":"1Lu4o8XVMM/Rg7GKAQAAAAEAAAAAAAAA/8tXQ36mEd90OaAOzCOSti7N5a2jr0B9ek48/uvyteG/zUJHyM16Hs3wMEhDqTQGBwGhWSHEqXh0/5Jbz6tXsYHhDTMr1BOsn1zaavZScx/CkO5+Hd8Vx+zeFPREtQTe1y+JngXSIroezeyV0/zF4YC4vpug+OZtrEQLNEgwT2bjaqUyaKDbmzCNetd2Ff/eFfMFzinbzKVgXAC7T4YmDuowqXommEXLIBiYh2u4VagwJKZRw5OGZjnvqwyVpSPgGqLxGKUoFigh3NgC6EuGi17VIs5BLRZOIw7+OfbPgQQiKzjCxCk="}`) - - listOpts := &KeyProviderListOpts{ - file: "test", - fs: afero.NewMemMapFs(), - } - bufOut := new(bytes.Buffer) - _ = listOpts.InitOutput(bufOut, listTmpl)() - _ = afero.WriteFile(listOpts.fs, "test", fileJSON, 0600) - - if err := listOpts.Run(); err != nil { - t.Fatalf("Run() unexpected error: %v", err) - } - - expected := `local: Filename = localKey -kmip: Unique Key ID = "uniqueKeyID" KMIP Server Name = "[kmipServerName]" KMIP Port = "8081" Key Wrap Method = "get" -` - if bufOut.String() != expected { - t.Fatalf("Run() expected: %s got: %v", expected, bufOut.String()) - } -} diff --git a/internal/decryption/audit_log_line_scanner.go b/internal/decryption/audit_log_line_scanner.go index 1c4b791180..9fbc0dba2c 100644 --- a/internal/decryption/audit_log_line_scanner.go +++ b/internal/decryption/audit_log_line_scanner.go @@ -56,12 +56,12 @@ func peekFirstByte(reader io.ReadSeeker) (byte, error) { return b[0], nil } -func readAuditLogFile(reader io.ReadSeeker) (AuditLogFormat, auditLogScanner, error) { +func readAuditLogFile(reader io.ReadSeeker) (auditLogScanner, error) { auditLogFormat := BSON b, err := peekFirstByte(reader) if err != nil { - return auditLogFormat, nil, err + return nil, err } if b == '{' { @@ -75,7 +75,7 @@ func readAuditLogFile(reader io.ReadSeeker) (AuditLogFormat, auditLogScanner, er case JSON: scanner = newJSONScanner(reader) } - return auditLogFormat, scanner, err + return scanner, err } type auditLogScanner interface { diff --git a/internal/decryption/audit_log_line_scanner_test.go b/internal/decryption/audit_log_line_scanner_test.go deleted file mode 100644 index 5e34abefc0..0000000000 --- a/internal/decryption/audit_log_line_scanner_test.go +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright 2022 MongoDB Inc -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//go:build unit - -package decryption - -import ( - "bytes" - "encoding/base64" - "testing" - "time" - - "github.com/go-test/deep" - "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/decryption/keyproviders" - "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/pointer" -) - -func buildExpectedLog() []*AuditLogLine { - ts := time.UnixMilli(1647253664552) - provider := keyproviders.LocalKey - encryptedKey, _ := base64.StdEncoding.DecodeString("9Jmg+S67unj4GfLfl4PxmSdo87e1dbtQ0UMrdid7tx7R42XhvtJnoLztSUhYQhWzIne/sNXvPIVl94M9VnXi+g==") - mac := "OG/VwMlpPU9ChDmHAQAAAAAAAAAAAAAA" - tsLog := time.UnixMilli(1647253664553) - recordTypeLog := AuditLogRecord - - return []*AuditLogLine{ - { - TS: &ts, - Version: pointer.Get("0.0"), - CompressionMode: pointer.Get("zstd"), - KeyStoreIdentifier: AuditLogLineKeyStoreIdentifier{ - Provider: &provider, - Filename: "localKey", - }, - EncryptedKey: encryptedKey, - MAC: &mac, - AuditRecordType: AuditHeaderRecord, - }, - { - TS: &tsLog, - AuditRecordType: recordTypeLog, - Log: pointer.Get("0QjwufYIydvNuDXTAQAAAAEAAAAAAAAAUZaMkB7yYllyHE8zES4A+BK5HODkhWjTBT9Yq/vwG3Tv8W4kEgED40aDMp8LLQbWzO/gTC+MzGSnHFqer6DgW9T1a7g4GqLlZBmP9WJhYxM+2yDURVsKuoghKlWlosXVGgd1GPD7PexRk8gytjVeFFxYTolPOwbLeek3feaMT1vThflfkAefc+VhUSfxkctX8NKvtY1CLLjrOyzXEG0OOBainbXiybCAyszDC9WdL0Cg8wx5kn4LXQHshFjCWA8GMIWQ8MNU7dmhx1mcEoKGrpdVeP/yQNOxSjkKDrC2o1P0wXigOZ8zRz/W"), - }, - } -} - -func Test_readAuditLogFile(t *testing.T) { - inputJSON := []byte(`{"ts":{"$date":{"$numberLong":"1647253664552"}},"auditrecordtype":"header","version":"0.0","compressionmode":"zstd","keystoreidentifier":{"provider":"local","filename":"localKey"},"encryptedkey":{"$binary":{"base64":"9Jmg+S67unj4GfLfl4PxmSdo87e1dbtQ0UMrdid7tx7R42XhvtJnoLztSUhYQhWzIne/sNXvPIVl94M9VnXi+g==","subType":"00"}},"mac":"OG/VwMlpPU9ChDmHAQAAAAAAAAAAAAAA"} -{"ts":{"$date":{"$numberLong":"1647253664553"}},"log":"0QjwufYIydvNuDXTAQAAAAEAAAAAAAAAUZaMkB7yYllyHE8zES4A+BK5HODkhWjTBT9Yq/vwG3Tv8W4kEgED40aDMp8LLQbWzO/gTC+MzGSnHFqer6DgW9T1a7g4GqLlZBmP9WJhYxM+2yDURVsKuoghKlWlosXVGgd1GPD7PexRk8gytjVeFFxYTolPOwbLeek3feaMT1vThflfkAefc+VhUSfxkctX8NKvtY1CLLjrOyzXEG0OOBainbXiybCAyszDC9WdL0Cg8wx5kn4LXQHshFjCWA8GMIWQ8MNU7dmhx1mcEoKGrpdVeP/yQNOxSjkKDrC2o1P0wXigOZ8zRz/W"}`) - inputBSON, _ := base64.StdEncoding.DecodeString(`GQEAAAl0cwAoM/iHfwEAAAJ2ZXJzaW9uAAQAAAAwLjAAAmNvbXByZXNzaW9uTW9kZQAFAAAAenN0ZAADa2V5U3RvcmVJZGVudGlmaWVyADAAAAACcHJvdmlkZXIABgAAAGxvY2FsAAJmaWxlbmFtZQAJAAAAbG9jYWxLZXkAAAVlbmNyeXB0ZWRLZXkAQAAAAAD0maD5Lru6ePgZ8t+Xg/GZJ2jzt7V1u1DRQyt2J3u3HtHjZeG+0megvO1JSFhCFbMid7+w1e88hWX3gz1WdeL6Ak1BQwAhAAAAT0cvVndNbHBQVTlDaERtSEFRQUFBQUFBQUFBQUFBQUEAAmF1ZGl0UmVjb3JkVHlwZQAHAAAAaGVhZGVyAABzAQAACXRzACkz+Id/AQAAAmxvZwBZAQAAMFFqd3VmWUl5ZHZOdURYVEFRQUFBQUVBQUFBQUFBQUFVWmFNa0I3eVlsbHlIRTh6RVM0QStCSzVIT0RraFdqVEJUOVlxL3Z3RzNUdjhXNGtFZ0VENDBhRE1wOExMUWJXek8vZ1RDK016R1NuSEZxZXI2RGdXOVQxYTdnNEdxTGxaQm1QOVdKaFl4TSsyeURVUlZzS3VvZ2hLbFdsb3NYVkdnZDFHUEQ3UGV4Ums4Z3l0alZlRkZ4WVRvbFBPd2JMZWVrM2ZlYU1UMXZUaGZsZmtBZWZjK1ZoVVNmeGtjdFg4Tkt2dFkxQ0xManJPeXpYRUcwT09CYWluYlhpeWJDQXlzekRDOVdkTDBDZzh3eDVrbjRMWFFIc2hGakNXQThHTUlXUThNTlU3ZG1oeDFtY0VvS0dycGRWZVAveVFOT3hTamtLRHJDMm8xUDB3WGlnT1o4elJ6L1cAAA==`) - - expectedLog := buildExpectedLog() - testCases := []struct { - name string - input []byte - expectedFormat AuditLogFormat - expectedLog []*AuditLogLine - }{ - { - name: "json", - input: inputJSON, - expectedFormat: JSON, - expectedLog: expectedLog, - }, - { - name: "bson", - input: inputBSON, - expectedFormat: BSON, - expectedLog: expectedLog, - }, - } - for _, tt := range testCases { - input := tt.input - expectedFormat := tt.expectedFormat - el := expectedLog - t.Run(tt.name, func(t *testing.T) { - format, scanner, err := readAuditLogFile(bytes.NewReader(input)) - if err != nil { - t.Fatal(err) - } - if expectedFormat != format { - t.Fatalf("expected: %v got: %v", expectedFormat, format) - } - var logs []*AuditLogLine - for scanner.Scan() { - log, err2 := scanner.AuditLogLine() - if err2 != nil { - t.Fatal(err2) - } - logs = append(logs, log) - } - if scanner.Err() != nil { - t.Fatal(scanner.Err()) - } - - if diff := deep.Equal(el, logs); diff != nil { - t.Error(diff) - } - }) - } -} - -func Test_readAuditLogFile_corruptedBSON(t *testing.T) { - expectedLog := buildExpectedLog() - - testCases := []struct { - name string - input string - expectErr bool - expectedLog []*AuditLogLine - }{ - { - name: "valid", - input: `GQEAAAl0cwAoM/iHfwEAAAJ2ZXJzaW9uAAQAAAAwLjAAAmNvbXByZXNzaW9uTW9kZQAFAAAAenN0ZAADa2V5U3RvcmVJZGVudGlmaWVyADAAAAACcHJvdmlkZXIABgAAAGxvY2FsAAJmaWxlbmFtZQAJAAAAbG9jYWxLZXkAAAVlbmNyeXB0ZWRLZXkAQAAAAAD0maD5Lru6ePgZ8t+Xg/GZJ2jzt7V1u1DRQyt2J3u3HtHjZeG+0megvO1JSFhCFbMid7+w1e88hWX3gz1WdeL6Ak1BQwAhAAAAT0cvVndNbHBQVTlDaERtSEFRQUFBQUFBQUFBQUFBQUEAAmF1ZGl0UmVjb3JkVHlwZQAHAAAAaGVhZGVyAABzAQAACXRzACkz+Id/AQAAAmxvZwBZAQAAMFFqd3VmWUl5ZHZOdURYVEFRQUFBQUVBQUFBQUFBQUFVWmFNa0I3eVlsbHlIRTh6RVM0QStCSzVIT0RraFdqVEJUOVlxL3Z3RzNUdjhXNGtFZ0VENDBhRE1wOExMUWJXek8vZ1RDK016R1NuSEZxZXI2RGdXOVQxYTdnNEdxTGxaQm1QOVdKaFl4TSsyeURVUlZzS3VvZ2hLbFdsb3NYVkdnZDFHUEQ3UGV4Ums4Z3l0alZlRkZ4WVRvbFBPd2JMZWVrM2ZlYU1UMXZUaGZsZmtBZWZjK1ZoVVNmeGtjdFg4Tkt2dFkxQ0xManJPeXpYRUcwT09CYWluYlhpeWJDQXlzekRDOVdkTDBDZzh3eDVrbjRMWFFIc2hGakNXQThHTUlXUThNTlU3ZG1oeDFtY0VvS0dycGRWZVAveVFOT3hTamtLRHJDMm8xUDB3WGlnT1o4elJ6L1cAAA==`, - expectErr: false, - }, - { - name: "tampered first byte, doc size would be wrong 279 instead of 281", - input: `FwEAAAl0cwAoM/iHfwEAAAJ2ZXJzaW9uAAQAAAAwLjAAAmNvbXByZXNzaW9uTW9kZQAFAAAAenN0ZAADa2V5U3RvcmVJZGVudGlmaWVyADAAAAACcHJvdmlkZXIABgAAAGxvY2FsAAJmaWxlbmFtZQAJAAAAbG9jYWxLZXkAAAVlbmNyeXB0ZWRLZXkAQAAAAAD0maD5Lru6ePgZ8t+Xg/GZJ2jzt7V1u1DRQyt2J3u3HtHjZeG+0megvO1JSFhCFbMid7+w1e88hWX3gz1WdeL6Ak1BQwAhAAAAT0cvVndNbHBQVTlDaERtSEFRQUFBQUFBQUFBQUFBQUEAAmF1ZGl0UmVjb3JkVHlwZQAHAAAAaGVhZGVyAABzAQAACXRzACkz+Id/AQAAAmxvZwBZAQAAMFFqd3VmWUl5ZHZOdURYVEFRQUFBQUVBQUFBQUFBQUFVWmFNa0I3eVlsbHlIRTh6RVM0QStCSzVIT0RraFdqVEJUOVlxL3Z3RzNUdjhXNGtFZ0VENDBhRE1wOExMUWJXek8vZ1RDK016R1NuSEZxZXI2RGdXOVQxYTdnNEdxTGxaQm1QOVdKaFl4TSsyeURVUlZzS3VvZ2hLbFdsb3NYVkdnZDFHUEQ3UGV4Ums4Z3l0alZlRkZ4WVRvbFBPd2JMZWVrM2ZlYU1UMXZUaGZsZmtBZWZjK1ZoVVNmeGtjdFg4Tkt2dFkxQ0xManJPeXpYRUcwT09CYWluYlhpeWJDQXlzekRDOVdkTDBDZzh3eDVrbjRMWFFIc2hGakNXQThHTUlXUThNTlU3ZG1oeDFtY0VvS0dycGRWZVAveVFOT3hTamtLRHJDMm8xUDB3WGlnT1o4elJ6L1cAAA==`, - expectErr: true, - }, - { - name: "tampered first byte, doc size would be wrong 283 instead of 281", - input: `GwEAAAl0cwAoM/iHfwEAAAJ2ZXJzaW9uAAQAAAAwLjAAAmNvbXByZXNzaW9uTW9kZQAFAAAAenN0ZAADa2V5U3RvcmVJZGVudGlmaWVyADAAAAACcHJvdmlkZXIABgAAAGxvY2FsAAJmaWxlbmFtZQAJAAAAbG9jYWxLZXkAAAVlbmNyeXB0ZWRLZXkAQAAAAAD0maD5Lru6ePgZ8t+Xg/GZJ2jzt7V1u1DRQyt2J3u3HtHjZeG+0megvO1JSFhCFbMid7+w1e88hWX3gz1WdeL6Ak1BQwAhAAAAT0cvVndNbHBQVTlDaERtSEFRQUFBQUFBQUFBQUFBQUEAAmF1ZGl0UmVjb3JkVHlwZQAHAAAAaGVhZGVyAABzAQAACXRzACkz+Id/AQAAAmxvZwBZAQAAMFFqd3VmWUl5ZHZOdURYVEFRQUFBQUVBQUFBQUFBQUFVWmFNa0I3eVlsbHlIRTh6RVM0QStCSzVIT0RraFdqVEJUOVlxL3Z3RzNUdjhXNGtFZ0VENDBhRE1wOExMUWJXek8vZ1RDK016R1NuSEZxZXI2RGdXOVQxYTdnNEdxTGxaQm1QOVdKaFl4TSsyeURVUlZzS3VvZ2hLbFdsb3NYVkdnZDFHUEQ3UGV4Ums4Z3l0alZlRkZ4WVRvbFBPd2JMZWVrM2ZlYU1UMXZUaGZsZmtBZWZjK1ZoVVNmeGtjdFg4Tkt2dFkxQ0xManJPeXpYRUcwT09CYWluYlhpeWJDQXlzekRDOVdkTDBDZzh3eDVrbjRMWFFIc2hGakNXQThHTUlXUThNTlU3ZG1oeDFtY0VvS0dycGRWZVAveVFOT3hTamtLRHJDMm8xUDB3WGlnT1o4elJ6L1cAAA==`, - expectErr: true, - }, - { - name: "tampered last byte to be 1 instead of 0", - input: `GQEAAAl0cwAoM/iHfwEAAAJ2ZXJzaW9uAAQAAAAwLjAAAmNvbXByZXNzaW9uTW9kZQAFAAAAenN0ZAADa2V5U3RvcmVJZGVudGlmaWVyADAAAAACcHJvdmlkZXIABgAAAGxvY2FsAAJmaWxlbmFtZQAJAAAAbG9jYWxLZXkAAAVlbmNyeXB0ZWRLZXkAQAAAAAD0maD5Lru6ePgZ8t+Xg/GZJ2jzt7V1u1DRQyt2J3u3HtHjZeG+0megvO1JSFhCFbMid7+w1e88hWX3gz1WdeL6Ak1BQwAhAAAAT0cvVndNbHBQVTlDaERtSEFRQUFBQUFBQUFBQUFBQUEAAmF1ZGl0UmVjb3JkVHlwZQAHAAAAaGVhZGVyAABzAQAACXRzACkz+Id/AQAAAmxvZwBZAQAAMFFqd3VmWUl5ZHZOdURYVEFRQUFBQUVBQUFBQUFBQUFVWmFNa0I3eVlsbHlIRTh6RVM0QStCSzVIT0RraFdqVEJUOVlxL3Z3RzNUdjhXNGtFZ0VENDBhRE1wOExMUWJXek8vZ1RDK016R1NuSEZxZXI2RGdXOVQxYTdnNEdxTGxaQm1QOVdKaFl4TSsyeURVUlZzS3VvZ2hLbFdsb3NYVkdnZDFHUEQ3UGV4Ums4Z3l0alZlRkZ4WVRvbFBPd2JMZWVrM2ZlYU1UMXZUaGZsZmtBZWZjK1ZoVVNmeGtjdFg4Tkt2dFkxQ0xManJPeXpYRUcwT09CYWluYlhpeWJDQXlzekRDOVdkTDBDZzh3eDVrbjRMWFFIc2hGakNXQThHTUlXUThNTlU3ZG1oeDFtY0VvS0dycGRWZVAveVFOT3hTamtLRHJDMm8xUDB3WGlnT1o4elJ6L1cAAQ==`, - expectErr: true, - }, - { - name: "tampered ts type from 0x9 UTC datetime to 0x13 decimal128", - input: `GQEAABN0cwAoM/iHfwEAAAJ2ZXJzaW9uAAQAAAAwLjAAAmNvbXByZXNzaW9uTW9kZQAFAAAAenN0ZAADa2V5U3RvcmVJZGVudGlmaWVyADAAAAACcHJvdmlkZXIABgAAAGxvY2FsAAJmaWxlbmFtZQAJAAAAbG9jYWxLZXkAAAVlbmNyeXB0ZWRLZXkAQAAAAAD0maD5Lru6ePgZ8t+Xg/GZJ2jzt7V1u1DRQyt2J3u3HtHjZeG+0megvO1JSFhCFbMid7+w1e88hWX3gz1WdeL6Ak1BQwAhAAAAT0cvVndNbHBQVTlDaERtSEFRQUFBQUFBQUFBQUFBQUEAAmF1ZGl0UmVjb3JkVHlwZQAHAAAAaGVhZGVyAABzAQAACXRzACkz+Id/AQAAAmxvZwBZAQAAMFFqd3VmWUl5ZHZOdURYVEFRQUFBQUVBQUFBQUFBQUFVWmFNa0I3eVlsbHlIRTh6RVM0QStCSzVIT0RraFdqVEJUOVlxL3Z3RzNUdjhXNGtFZ0VENDBhRE1wOExMUWJXek8vZ1RDK016R1NuSEZxZXI2RGdXOVQxYTdnNEdxTGxaQm1QOVdKaFl4TSsyeURVUlZzS3VvZ2hLbFdsb3NYVkdnZDFHUEQ3UGV4Ums4Z3l0alZlRkZ4WVRvbFBPd2JMZWVrM2ZlYU1UMXZUaGZsZmtBZWZjK1ZoVVNmeGtjdFg4Tkt2dFkxQ0xManJPeXpYRUcwT09CYWluYlhpeWJDQXlzekRDOVdkTDBDZzh3eDVrbjRMWFFIc2hGakNXQThHTUlXUThNTlU3ZG1oeDFtY0VvS0dycGRWZVAveVFOT3hTamtLRHJDMm8xUDB3WGlnT1o4elJ6L1cAAA==`, - expectErr: true, - }, - } - for _, tt := range testCases { - input := tt.input - expectErr := tt.expectErr - t.Run(tt.name, func(t *testing.T) { - buf, err := base64.StdEncoding.DecodeString(input) - if err != nil { - t.Fatal(err) - } - - format, scanner, err := readAuditLogFile(bytes.NewReader(buf)) - if err != nil && !expectErr { - t.Fatal(err) - } - if format != BSON { - t.Errorf("expected: BSON got: %v", format) - } - - var logs []*AuditLogLine - for scanner.Scan() { - log, err2 := scanner.AuditLogLine() - if err2 != nil && !expectErr { - t.Fatal(err2) - } - logs = append(logs, log) - } - if scanner.Err() != nil && !expectErr { - t.Fatal(scanner.Err()) - } - - if diff := deep.Equal(expectedLog, logs); expectErr && diff == nil { - t.Error("expected failure but decrypted correctly") - } - }) - } -} diff --git a/internal/decryption/decryption.go b/internal/decryption/decryption.go index d9a0b8cc3a..829b3598ba 100644 --- a/internal/decryption/decryption.go +++ b/internal/decryption/decryption.go @@ -79,7 +79,7 @@ func WithAzureOpts(tenantID, clientID, secret string) func(d *Decryption) { // the credentials provided by the user and the AES-GCM algorithm. // The decrypted audit log records are saved in the out stream. func (d *Decryption) Decrypt(logReader io.ReadSeeker, out io.Writer) error { - _, logLineScanner, err := readAuditLogFile(logReader) + logLineScanner, err := readAuditLogFile(logReader) if err != nil { return err } diff --git a/internal/decryption/encrypted_audit_log.go b/internal/decryption/encrypted_audit_log.go index 1c653be6bc..2dd56eabd2 100644 --- a/internal/decryption/encrypted_audit_log.go +++ b/internal/decryption/encrypted_audit_log.go @@ -32,13 +32,6 @@ type AuditRecordType string type AuditLogLineKeyStoreIdentifier struct { Provider *keyproviders.KeyStoreProvider `json:"provider,omitempty"` - // localKey - Filename string `json:"filename,omitempty"` - // kmip - UID string `json:"uniqueKeyID,omitempty"` - KMIPServerName []string `json:"kmipServerName,omitempty"` - KMIPPort int `json:"kmipPort,omitempty"` - KeyWrapMethod keyproviders.KMIPKeyWrapMethod `json:"keyWrapMethod,omitempty"` // aws Key string `json:"key,omitempty"` Region string `json:"region,omitempty"` @@ -76,29 +69,6 @@ func (logLine *AuditLogLine) KeyProvider(opts KeyProviderOpts) (keyproviders.Key } switch *logLine.KeyStoreIdentifier.Provider { - case keyproviders.LocalKey: - if opts.Local == nil { - return nil, fmt.Errorf("%w: %s", ErrKeyProviderNotSupported, *logLine.KeyStoreIdentifier.Provider) - } - return &keyproviders.LocalKeyIdentifier{ - HeaderFilename: logLine.KeyStoreIdentifier.Filename, - Filename: opts.Local.KeyFileName, - }, nil - case keyproviders.KMIP: - if opts.KMIP == nil { - return nil, fmt.Errorf("%w: %s", ErrKeyProviderNotSupported, *logLine.KeyStoreIdentifier.Provider) - } - return &keyproviders.KMIPKeyIdentifier{ - UniqueKeyID: logLine.KeyStoreIdentifier.UID, - ServerNames: logLine.KeyStoreIdentifier.KMIPServerName, - ServerPort: logLine.KeyStoreIdentifier.KMIPPort, - KeyWrapMethod: logLine.KeyStoreIdentifier.KeyWrapMethod, - ServerCAFileName: opts.KMIP.ServerCAFileName, - ClientCertificateFileName: opts.KMIP.ClientCertificateFileName, - ClientCertificatePassword: opts.KMIP.ClientCertificatePassword, - Username: opts.KMIP.Username, - Password: opts.KMIP.Password, - }, nil case keyproviders.AWS: if opts.AWS == nil { return nil, fmt.Errorf("%w: %s", ErrKeyProviderNotSupported, *logLine.KeyStoreIdentifier.Provider) diff --git a/internal/decryption/header_test.go b/internal/decryption/header_test.go index 023ea31f05..e5f09013b4 100644 --- a/internal/decryption/header_test.go +++ b/internal/decryption/header_test.go @@ -18,6 +18,7 @@ package decryption import ( "encoding/base64" + "fmt" "testing" "time" @@ -96,7 +97,7 @@ func Test_validateMAC(t *testing.T) { func Test_validateHeaderFields(t *testing.T) { ts := time.Now() invalidCompressionMode := "foo" - provider := keyproviders.LocalKey + provider := keyproviders.Azure encryptedKey := []byte{0, 1, 2, 3} testCases := []struct { @@ -225,12 +226,16 @@ func Test_validateHeaderFields(t *testing.T) { expectErr: true, }, } - for _, testCase := range testCases { - err := validateHeaderFields(pointer.Get(testCase.input)) - if testCase.expectErr && err == nil { - t.Errorf("expected: not nil got: %v", err) - } else if !testCase.expectErr && err != nil { - t.Errorf("expected: nil got: %v", err) - } + for i, tc := range testCases { + tt := tc + t.Run(fmt.Sprintf("test_%d", i), func(t *testing.T) { + t.Parallel() + err := validateHeaderFields(&tt.input) + if tt.expectErr && err == nil { + t.Errorf("expected: not nil got: %v", err) + } else if !tt.expectErr && err != nil { + t.Errorf("expected: nil got: %v", err) + } + }) } } diff --git a/internal/decryption/keyproviders/key_provider.go b/internal/decryption/keyproviders/key_provider.go index 26ec719a29..185734db01 100644 --- a/internal/decryption/keyproviders/key_provider.go +++ b/internal/decryption/keyproviders/key_provider.go @@ -24,11 +24,9 @@ import ( type KeyStoreProvider string const ( - LocalKey KeyStoreProvider = "local" - KMIP KeyStoreProvider = "kmip" - AWS KeyStoreProvider = "aws" - GCP KeyStoreProvider = "gcp" - Azure KeyStoreProvider = "azure" + AWS KeyStoreProvider = "aws" + GCP KeyStoreProvider = "gcp" + Azure KeyStoreProvider = "azure" ) type KeyProvider interface { diff --git a/internal/decryption/keyproviders/kmip.go b/internal/decryption/keyproviders/kmip.go deleted file mode 100644 index c645151b28..0000000000 --- a/internal/decryption/keyproviders/kmip.go +++ /dev/null @@ -1,257 +0,0 @@ -// Copyright 2022 MongoDB Inc -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package keyproviders - -import ( - "errors" - "fmt" - "os" - "strings" - - "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/decryption/aes" - "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/decryption/kmip" - "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/decryption/pem" - "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/log" - "go.mongodb.org/mongo-driver/bson" -) - -type KMIPKeyWrapMethod string - -const ( - KMIPKeyWrapMethodGet KMIPKeyWrapMethod = "get" - KMIPKeyWrapMethodEncrypt KMIPKeyWrapMethod = "encrypt" -) - -// LocalKeyIdentifier config for the KMIP speaking server used to encrypt the Log Encryption Key (LEK). -type KMIPKeyIdentifier struct { - KeyStoreIdentifier - - // Header - UniqueKeyID string - ServerNames []string - ServerPort int - KeyWrapMethod KMIPKeyWrapMethod - - // CLI - ServerCAFileName string - ClientCertificateFileName string - ClientCertificatePassword string - Username string - Password string -} - -// KMIPEncryptedKey encrypted LEK and tag, BSON marshaled. -type KMIPEncryptedKey struct { - IV []byte - Key []byte -} - -var ( - ErrKMIPServerCAMissing = errors.New("server CA missing") - ErrKMIPClientCertificateMissing = errors.New("client certificate missing") - ErrKMIPServerNamesMissing = errors.New("server name is not provided") - ErrKMIPPasswordMissing = errors.New("password is not provided") - ErrKMIPClientCertificatePasswordMissing = errors.New("password for client certificate is not provided") -) - -func (ki *KMIPKeyIdentifier) ValidateCredentials() error { - if ki.ServerCAFileName == "" || ki.ClientCertificateFileName == "" { - _, err := log.Warningf(`No credentials found for resource: KMIP uniqueKeyID="%v" serverNames="%v" serverPort="%v" keyWrapMethod="%v" -`, ki.UniqueKeyID, strings.Join(ki.ServerNames, "; "), ki.ServerPort, ki.KeyWrapMethod) - if err != nil { - return err - } - } - - if err := ki.validateServerCA(); err != nil { - return err - } - - if err := ki.validateClientCert(); err != nil { - return err - } - - return ki.validateUsernameAndPassword() -} - -// DecryptKey decrypts LEK using KMIP get or decrypt methods. -func (ki *KMIPKeyIdentifier) DecryptKey(encryptedKey []byte) ([]byte, error) { - if len(ki.ServerNames) == 0 { - return nil, ErrKMIPServerNamesMissing - } - - kmipEncryptedKey, err := decodeEncryptedKey(encryptedKey) - if err != nil { - return nil, err - } - - var clientError error - collectErr := func(err error, serverName string) { - if clientError == nil { - clientError = err - } else { - clientError = fmt.Errorf("'%s': %w", serverName, err) - } - } - - for _, serverName := range ki.ServerNames { - kmipClient, err := ki.kmipClient(serverName) - if err != nil { - // init KMIP client error (invalid config), skip other KMIP servers - return nil, err - } - - var key []byte - if ki.KeyWrapMethod == KMIPKeyWrapMethodEncrypt { - key, err = ki.decryptWithKeyWrapMethodEncrypt(kmipClient, kmipEncryptedKey) - } else { - key, err = ki.decryptWithKeyWrapMethodGet(kmipClient, kmipEncryptedKey) - } - - if err == nil { - // key successfully decrypted, skip other KMIP servers and return decrypted key - return key, nil - } - collectErr(err, serverName) - } - - return nil, clientError -} - -func (ki *KMIPKeyIdentifier) validateUsernameAndPassword() error { - if ki.Username != "" && ki.Password == "" { - p, err := provideInput("Provide password for \""+ki.Username+"\":", "") - if err != nil { - return err - } - ki.Password = p - if ki.Password == "" { - return ErrKMIPPasswordMissing - } - } - return nil -} - -func (ki *KMIPKeyIdentifier) validateServerCA() error { - if ki.ServerCAFileName == "" { - f, err := provideInput("Provide server CA filename:", "") - if err != nil { - return err - } - ki.ServerCAFileName = f - if ki.ServerCAFileName == "" { - return ErrKMIPServerCAMissing - } - } - - if _, err := pem.ValidateBlocks(ki.ServerCAFileName); err != nil { - return fmt.Errorf("server CA %w", err) - } - return nil -} - -func (ki *KMIPKeyIdentifier) validateClientCert() error { - if ki.ClientCertificateFileName == "" { - f, err := provideInput("Provide client certificate filename:", "") - if err != nil { - return err - } - ki.ClientCertificateFileName = f - if ki.ClientCertificateFileName == "" { - return ErrKMIPClientCertificateMissing - } - } - - isEncrypted, err := pem.ValidateBlocks(ki.ClientCertificateFileName) - if err != nil { - return fmt.Errorf("client certificate %w", err) - } - - if isEncrypted && ki.ClientCertificatePassword == "" { - p, err := provideInput("Provide password for client certificate:", "") - if err != nil { - return err - } - ki.ClientCertificatePassword = p - if ki.ClientCertificatePassword == "" { - return ErrKMIPClientCertificatePasswordMissing - } - } - - return nil -} - -func (ki *KMIPKeyIdentifier) decryptWithKeyWrapMethodEncrypt(kmipClient *kmip.Client, kmipEncryptedKey *KMIPEncryptedKey) ([]byte, error) { - decryptedLEK, err := kmipClient.Decrypt(ki.UniqueKeyID, kmipEncryptedKey.Key, kmipEncryptedKey.IV) - if err != nil { - return nil, err - } - return decryptedLEK.Data, nil -} - -func (ki *KMIPKeyIdentifier) decryptWithKeyWrapMethodGet(kmipClient *kmip.Client, kmipEncryptedKey *KMIPEncryptedKey) ([]byte, error) { - kek, err := kmipClient.GetSymmetricKey(ki.UniqueKeyID) - if err != nil { - return nil, err - } - - tag := kmipEncryptedKey.Key[0:12] - cipherText := kmipEncryptedKey.Key[12:] - aad := []byte(ki.UniqueKeyID) - iv := kmipEncryptedKey.IV - - gcm := &aes.GCMInput{Key: kek, AAD: aad, IV: iv, Tag: tag} - decryptedLEK, err := gcm.Decrypt(cipherText) - if err != nil { - return nil, err - } - return decryptedLEK, nil -} - -func decodeEncryptedKey(encryptedKey []byte) (*KMIPEncryptedKey, error) { - var kmipEncryptedKey KMIPEncryptedKey - if err := bson.Unmarshal(encryptedKey, &kmipEncryptedKey); err != nil { - return nil, err - } - return &kmipEncryptedKey, nil -} - -func (ki *KMIPKeyIdentifier) kmipClient(serverName string) (*kmip.Client, error) { - rootCA, err := os.ReadFile(ki.ServerCAFileName) - if err != nil { - return nil, err - } - - version := kmip.V12 - if ki.KeyWrapMethod == KMIPKeyWrapMethodGet { - version = kmip.V10 - } - - clientCert, clientPrivateKey, err := pem.Decode(ki.ClientCertificateFileName, ki.ClientCertificatePassword) - if err != nil { - return nil, fmt.Errorf("error parsing client certificate: %w", err) - } - - return kmip.NewClient(&kmip.Config{ - Version: version, - Hostname: serverName, - Port: ki.ServerPort, - RootCertificate: rootCA, - ClientPrivateKey: clientPrivateKey, - ClientCertificate: clientCert, - Username: ki.Username, - Password: ki.Password, - }) -} diff --git a/internal/decryption/keyproviders/local_key.go b/internal/decryption/keyproviders/local_key.go deleted file mode 100644 index 86961ed0e2..0000000000 --- a/internal/decryption/keyproviders/local_key.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2022 MongoDB Inc -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package keyproviders - -import ( - "encoding/base64" - "errors" - "os" - - "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/decryption/aes" - "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/log" -) - -// LocalKeyIdentifier config for the localKey used to encrypt the Log Encryption Key (LEK). -type LocalKeyIdentifier struct { - KeyStoreIdentifier - - // Header - HeaderFilename string - - // CLI - Filename string -} - -var ErrLocalKeyCredentialMissing = errors.New("filename missing") - -func (ki *LocalKeyIdentifier) ValidateCredentials() error { - if ki.Filename == "" { - _, _ = log.Warningf(`No credentials found for resource: LocalKey filename="%v" -`, ki.HeaderFilename) - - f, err := provideInput("Provide key filename:", "") - if err != nil { - return err - } - ki.Filename = f - if ki.Filename == "" { - return ErrLocalKeyCredentialMissing - } - } - return nil -} - -// DecryptKey decrypts LEK using KMIP get or decrypt methods. -func (ki *LocalKeyIdentifier) DecryptKey(encryptedKey []byte) ([]byte, error) { - encodedKEK, err := os.ReadFile(ki.Filename) - if err != nil { - return nil, err - } - - kek, err := base64.StdEncoding.DecodeString(string(encodedKEK)) - if err != nil { - return nil, err - } - - iv := encryptedKey[:16] - encryptedLEK := encryptedKey[16:48] - - cbc := &aes.CBCInput{ - Key: kek, - IV: iv, - } - return cbc.Decrypt(encryptedLEK) -} diff --git a/internal/decryption/list_providers.go b/internal/decryption/list_providers.go index 11e2d26e13..b7049d3f85 100644 --- a/internal/decryption/list_providers.go +++ b/internal/decryption/list_providers.go @@ -21,7 +21,7 @@ import ( ) func ListKeyProviders(logReader io.ReadSeeker) ([]*AuditLogLineKeyStoreIdentifier, error) { - _, logLineScanner, err := readAuditLogFile(logReader) + logLineScanner, err := readAuditLogFile(logReader) if err != nil { return nil, err }