diff --git a/cmd/utils.go b/cmd/utils.go index add5701..0160f9f 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -8,8 +8,11 @@ import ( "encoding/pem" "fmt" "log/slog" + "os" "time" + "golang.org/x/term" + avs "github.com/aerospike/avs-client-go" ) @@ -26,9 +29,21 @@ func createClientFromFlags(clientFlags *flags.ClientFlags, connectTimeout time.D } var password *string - if len(clientFlags.Password) != 0 { - strPass := clientFlags.Password.String() - password = &strPass + if clientFlags.User.Val != nil { + if len(clientFlags.Password) != 0 { + strPass := clientFlags.Password.String() + password = &strPass + } else { + fmt.Print("Enter Password: ") + bytePassword, err := term.ReadPassword(int(os.Stdin.Fd())) + if err != nil { + logger.Error("failed to read password", slog.Any("error", err)) + return nil, err + } + fmt.Println() // Print a newline after the password input + strPass := string(bytePassword) + password = &strPass + } } adminClient, err := avs.NewAdminClient( diff --git a/docker/mtls/config/aerospike-proximus.yml b/docker/mtls/config/aerospike-proximus.yml new file mode 100644 index 0000000..60473cf --- /dev/null +++ b/docker/mtls/config/aerospike-proximus.yml @@ -0,0 +1,87 @@ +# Change the configuration for your use case. +cluster: + # Custom node-id. It will be auto-generated if not specified. + # node-id: a1 + + # Unique identifier for this cluster. + cluster-name: prism-image-search + +tls: + service-tls: + mutual-auth: true + trust-store: + store-file: /etc/aerospike-proximus/tls/ca.aerospike.com.truststore.jks + store-password-file: /etc/aerospike-proximus/tls/storepass + key-store: + store-file: /etc/aerospike-proximus/tls/localhost.keystore.jks + store-password-file: /etc/aerospike-proximus/tls/storepass + key-password-file: /etc/aerospike-proximus/tls/keypass + +# The Proximus service listening ports, TLS and network interface. +service: + ports: + 10000: + # If TLS needs to be enabled, tls configuration id. + tls-id: service-tls + advertised-listeners: + default: + address: 127.0.0.1 + port: 10000 + +# Management API listening ports, TLS and network interface. +manage: + ports: + 5040: + tls-id: service-tls + +# Intra cluster interconnect listening ports, TLS and network interface. +interconnect: + ports: + 5001: {} + +#heartbeat: +# seeds: +# - address: localhost +# port: 6001 + +# Target Aerospike cluster +aerospike: + seeds: + - aerospike: + port: 3000 + +# File based credentials store only if security should be enabled. +#security: +# credentials-store: +# type: file +# credentials-file: samples/credentials.yml +# auth-token: +# private-key: samples/auth/private_key.pem +# public-key: samples/auth/public_key.pem + +# Vault based credentials store only if security should be enabled. +#security: +# credentials-store: +# type: vault +# url: https://vault:8200 +# secrets-path: /secret/aerospike/aerodb1 +# tls: +# key-store: +# store-type: PEM +# store-file: key.pem +# store-password-file: keypass.txt # Password protecting key.pem. +# certificate-chain-files: certchain.pem +# trust-store: +# store-type: PEM +# certificate-files: cacert.pem +# auth-token: +# private-key: samples/auth/private_key.pem +# public-key: samples/auth/public_key.pem + +# The logging properties. +logging: + #format: json + #file: /var/log/aerospike-proximus/aerospike-proximus.log + enable-console-logging: true + levels: + metrics-ticker: off diff --git a/docker/mtls/config/aerospike.conf b/docker/mtls/config/aerospike.conf new file mode 100644 index 0000000..a23c052 --- /dev/null +++ b/docker/mtls/config/aerospike.conf @@ -0,0 +1,82 @@ +# Aerospike database configuration file for use with systemd. + +service { + cluster-name prism-demo + proto-fd-max 15000 +} + + +logging { + file /var/log/aerospike/aerospike.log { + context any info + } + + # Send log messages to stdout + console { + context any info + context query critical + } +} + +network { + service { + address any + port 3000 + } + + heartbeat { + mode multicast + multicast-group 239.1.99.222 + port 9918 + + # To use unicast-mesh heartbeats, remove the 3 lines above, and see + # aerospike_mesh.conf for alternative. + + interval 150 + timeout 10 + } + + fabric { + port 3001 + } + + info { + port 3003 + } +} + +namespace test { + replication-factor 1 + nsup-period 60 + + storage-engine memory { + data-size 1G + } +} + +namespace bar { + replication-factor 1 + nsup-period 60 + + storage-engine memory { + data-size 1G + } +} + +namespace proximus-meta { + replication-factor 1 + nsup-period 100 + + storage-engine memory { + data-size 1G + } + + # To use file storage backing, comment out the line above and use the + # following lines instead. +# storage-engine device { +# file /opt/aerospike/data/bar.dat +# filesize 16G +# data-in-memory true # Store data in memory in addition to file. +# } +} + diff --git a/docker/mtls/config/tls/ca.aerospike.com.crt b/docker/mtls/config/tls/ca.aerospike.com.crt new file mode 100644 index 0000000..522410a --- /dev/null +++ b/docker/mtls/config/tls/ca.aerospike.com.crt @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID/jCCAuagAwIBAgIJALiEh0EwIowCMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD +VQQGEwJJTjELMAkGA1UECAwCS0ExCzAJBgNVBAcMAkJOMRIwEAYDVQQKDAlhZXJv +c3Bpa2UxEjAQBgNVBAsMCWVjb3N5c3RlbTEZMBcGA1UEAwwQY2EuYWVyb3NwaWtl +LmNvbTEfMB0GCSqGSIb3DQEJARYQY2FAYWVyb3NwaWtlLmNvbTAeFw0xOTA3MDgw +OTA2NTZaFw0zOTA3MDMwOTA2NTZaMIGLMQswCQYDVQQGEwJJTjELMAkGA1UECAwC +S0ExCzAJBgNVBAcMAkJOMRIwEAYDVQQKDAlhZXJvc3Bpa2UxEjAQBgNVBAsMCWVj +b3N5c3RlbTEZMBcGA1UEAwwQY2EuYWVyb3NwaWtlLmNvbTEfMB0GCSqGSIb3DQEJ +ARYQY2FAYWVyb3NwaWtlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAOkpqtQIiWhUouKqsyoHs7+mXL4fahOKZBG1asUaNpY/rhR500OpczWfHXK1 ++W5WA2yizhIFFpgzNJOtXW2Sai0Dqk5MO7hPLoKzlA/pSYnVFyM34kECWiqFo9PZ +6FQxOBfRJjE4sLuLJGh+Pr/bii8Cb8GwuckUGFQaJLv9VZXcsGkpvyOEy9CsRI7o +7wPn0VVNxj6bbag0AUCe5s1ZKsNxFh3Ekqbx+pFA/7KxxVSmOCVhX+W87K4qJz0+ +XfGtBJjM4YqGun3ul4JCzcPHoqA5vKAB00LHa7bNY/5Zf2iGcfPLEmyk09PyqAQF +KTj8D4OTiP85L+wo7jxY6U/Xz1cCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFEz8sA/FRlupRxPfrDrnFZwN4g+HMB8G +A1UdIwQYMBaAFEz8sA/FRlupRxPfrDrnFZwN4g+HMA0GCSqGSIb3DQEBCwUAA4IB +AQDTDCjMVX11S9GZGNExnqtGVzOEAlKyWnx0g1pULTffN3vc8DG1gynY6n7/9vPI +V2pheuyd/aKoR0Ig8CvjOnj90DcMePwh3Zk6eG7SlUK41x4yrkw04VEqvyw02Dw7 +SPZRgEs5/AHVLscOaDeJxW6Nzm5XYS5mfhto5nZCBEq5u5FfsktwYisIlK9JLbYE +ATjQbkwoNeg2Ubdtddn9HgnCEV0ht0VE2bZc0OUmv29R5XTNEIEIf/bXjdgnbv57 +IhJElLyHziPbD08JgkqqQw+6zAbxO9OLury69eUQoC0nynVX+Ub9GoXSuQ2lGyyq +ouSZQ0M5aZVQvsqUyREGBsAF +-----END CERTIFICATE----- diff --git a/docker/mtls/config/tls/ca.aerospike.com.truststore.jks b/docker/mtls/config/tls/ca.aerospike.com.truststore.jks new file mode 100644 index 0000000..8d72ac6 Binary files /dev/null and b/docker/mtls/config/tls/ca.aerospike.com.truststore.jks differ diff --git a/docker/mtls/config/tls/keypass b/docker/mtls/config/tls/keypass new file mode 100644 index 0000000..0f673cc --- /dev/null +++ b/docker/mtls/config/tls/keypass @@ -0,0 +1 @@ +citrusstore \ No newline at end of file diff --git a/docker/mtls/config/tls/localhost.crt b/docker/mtls/config/tls/localhost.crt new file mode 100644 index 0000000..e713708 --- /dev/null +++ b/docker/mtls/config/tls/localhost.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDhzCCAm+gAwIBAgIUES99at1e+OgIcnfEwS6+uBLdLlkwDQYJKoZIhvcNAQEL +BQAwgYsxCzAJBgNVBAYTAklOMQswCQYDVQQIDAJLQTELMAkGA1UEBwwCQk4xEjAQ +BgNVBAoMCWFlcm9zcGlrZTESMBAGA1UECwwJZWNvc3lzdGVtMRkwFwYDVQQDDBBj +YS5hZXJvc3Bpa2UuY29tMR8wHQYJKoZIhvcNAQkBFhBjYUBhZXJvc3Bpa2UuY29t +MB4XDTE5MDcxNDE3NTI1M1oXDTI5MDcxMTE3NTI1M1owSDELMAkGA1UEBhMCSU4x +CzAJBgNVBAgMAktBMRgwFgYDVQQKDA9BZXJvc3Bpa2UsIEluYy4xEjAQBgNVBAMM +CWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOOLzx9 +a8XnBLrTQn2RBJfUUi7qZZTBAEraQ0Tsh04wqEycwxsh4HfpqP4QDF8JpAs5mvMj +fotnamVCNncXJgvOIaPQVRoDdGAAfCcOvT9B0Y7xBH3jj+e9YBiOEfee7cb7mjnX +2XYa9UGepNIktHUR0RgsuNooxDcT8wIbt+QMK0ZqF5GBQtgX24646ow5VOzfAGZy +SZfc9J0mWIZwHc0Gkb+V15iJBzdwJ/15FrmHSiJqGIsesqThrdAh5SYZCG/1+RL8 +FuwtZuoKm3V4OoQzQ0TIz6fCaiLI1PgrKJnMiGa3PIPX5DyPEU+5opXJCClGW2iM +pGmDQ5W+GmZwickCAwEAAaMlMCMwIQYDVR0RBBowGIIJbG9jYWxob3N0ggsqLmxv +Y2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEAdVCQWrRC3bCI6nQ1GuEfbEa7Fn2x +88EvMoJb7PLCLnumDd68AJ38qHUrmvrTbFFJemrCJ2cI0vGQPf5bMm+L2KyxVD9D +zSyy/mbKmAvJl05gv+Si0N9Ikhnqyj9NuF2hnMVJp7IowCBWU/JTfmXJFJU+bJDr +NntdjuUGHYq+zlTPowGS1p1Bx5QC+6YpelAcYiV7JiUXPQXd0SpJMcp0iYhJLjHv +qoM/jPl0gIHrn8WMrIKmf81Uv3mNd2nkKhiNuqqrHs5tVarYHfY2IJVnf8nMKlh9 +LVUXkze20oB2uc6IKxrb7nbXk0Q2XKb9xmpaFb+Fut3musY5sYrE9l+bkw== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/docker/mtls/config/tls/localhost.key b/docker/mtls/config/tls/localhost.key new file mode 100644 index 0000000..23b929e --- /dev/null +++ b/docker/mtls/config/tls/localhost.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEA044vPH1rxecEutNCfZEEl9RSLupllMEAStpDROyHTjCoTJzD +GyHgd+mo/hAMXwmkCzma8yN+i2dqZUI2dxcmC84ho9BVGgN0YAB8Jw69P0HRjvEE +feOP571gGI4R957txvuaOdfZdhr1QZ6k0iS0dRHRGCy42ijENxPzAhu35AwrRmoX +kYFC2BfbjrjqjDlU7N8AZnJJl9z0nSZYhnAdzQaRv5XXmIkHN3An/XkWuYdKImoY +ix6ypOGt0CHlJhkIb/X5EvwW7C1m6gqbdXg6hDNDRMjPp8JqIsjU+CsomcyIZrc8 +g9fkPI8RT7milckIKUZbaIykaYNDlb4aZnCJyQIDAQABAoIBAQCntYX43Cy93KBB +Qwzo4jfT7TuheaxBuqbysAi38RJqh+RDp9p7/eUm6pNPpYVJKiljxKzzpuXAuaD8 +2Pq4eh9tKGI+rP9p+ecd3ASQKf0Y0qLAQI0hB2+jdNtjW+0ecl1pazgeNuFr4X8g +IBXlibeNPyyVj46TU9IJH8V7nGGxZArm5hOWbLxfygVzulkeEsozjeDcVaUZPA1o +gN9QgqSC850jjqddV7a0sZuHyd3KECkfU1uRoSHikTKHJLxaV6BIHzliQijRutLT +hTFpk4QzM+7xixY66hh56YAoTB44A0sXHNrH5Zt3YkUv4mT/P9ue9DQ1mhz2Eh4h +DAzWFq4BAoGBAPOCOyar6K0mogxUl1Q1LBH34HvyrZ4uVN7ICeE12neh/fS04fnV +lM5e6bxKj2HEzqqJ8JUxjQypurz6aQBSI1o0hc13eZqykoNa7c9TREY8swM4Vwl9 +NOdyBuysJIqG9+tPp+vReP4ISyLG8fyeJNDl1OEaaz2GcxPGDbf7hR1hAoGBAN5o +V0tXp5wG/RnUZn0FU2g8faw5tfB4iO38igYJPEo5YbiC7FcJHYiPUlEfjlWmWwGT +RNggYK6Q7lQ4NKJU80DTG2k5AK5yLHtmtRmPPhYMZAt5txCXF7zpuoQS7OTKnc4l +R9pnsEYn+kYN/YA3EC56j/uSj6VEdB/AgHNvs51pAoGBAN4DlrqjcfisiIKFfZOh +BxU60skvcWwPAgI8kAVtfEomv8wkPwPx30Jo9uJdeGzDa0nBij/8dYVeGovCI4nP +WbwctwGmNJD+zuZEOR4V5OHE5dHBxFk6dsmuBPIz4P0MIW3BqnAvBAlYtmh2yppv +9VEguv6hf7UQqEsW/9sGz08BAoGBAKMnripCMl3+rnvdWhYK6yYDgjnu2C6BbgoQ +Afztl4Hn2G0v9krfEABXC48hdBwW/poIPC/EiMhm379+v/X6Fb0PYQNu4rYWYdVh +Aieu8l/gVSAp+Qa9oJdgawhqjchFb0CEDtMEz8aXmzz7FGWTf1ZpaOinmqMltX55 +jIGihwRJAoGATH9eCCCv1rbdnM8+qY3R8PZcZAOugICN55woXHJBCRRT+CpY4kiG +LNXyLZILWs8LXbzkKtynCXmVHMGbehtY/PnGXoSpsgLLz15CuGrbyQLoLnTr8NTB +atV5a96f8fOPhFl9EIRzV8u3DIF4CoYvNAFws7VwPDw01FCw5MncX2g= +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/docker/mtls/config/tls/localhost.keystore.jks b/docker/mtls/config/tls/localhost.keystore.jks new file mode 100644 index 0000000..8062beb Binary files /dev/null and b/docker/mtls/config/tls/localhost.keystore.jks differ diff --git a/docker/mtls/config/tls/storepass b/docker/mtls/config/tls/storepass new file mode 100644 index 0000000..b1f833e --- /dev/null +++ b/docker/mtls/config/tls/storepass @@ -0,0 +1 @@ +citrusstore diff --git a/docker/mtls/docker-compose.yml b/docker/mtls/docker-compose.yml new file mode 100644 index 0000000..30a3af1 --- /dev/null +++ b/docker/mtls/docker-compose.yml @@ -0,0 +1,23 @@ +services: + aerospike: + image: aerospike/aerospike-server-enterprise:7.0.0.2 + ports: + - "3000:3000" + networks: + - avs-demo + volumes: + - ./config:/opt/aerospike/etc/aerospike + command: + - "--config-file" + - "/opt/aerospike/etc/aerospike/aerospike.conf" + avs: + image: aerospike.jfrog.io/docker/aerospike/aerospike-proximus-private:0.5.0-SNAPSHOT + ports: + - "10000:10000" + networks: + - avs-demo + volumes: + - ./config:/etc/aerospike-proximus + +networks: + avs-demo: {} diff --git a/e2e_test.go b/e2e_test.go index 27a3542..ecdd4d7 100644 --- a/e2e_test.go +++ b/e2e_test.go @@ -8,7 +8,6 @@ import ( "crypto/tls" "crypto/x509" "fmt" - "io/ioutil" "log" "log/slog" "os" @@ -21,6 +20,7 @@ import ( avs "github.com/aerospike/avs-client-go" "github.com/aerospike/avs-client-go/protos" + "github.com/aerospike/tools-common-go/client" "github.com/stretchr/testify/suite" ) @@ -35,16 +35,29 @@ var ( func GetCACert(cert string) (*x509.CertPool, error) { // read in file - certBytes, err := ioutil.ReadFile(cert) + certBytes, err := os.ReadFile(cert) if err != nil { log.Fatalf("unable to read cert file %v", err) return nil, err } - certificates := x509.NewCertPool() - certificates.AppendCertsFromPEM(certBytes) + return client.LoadCACerts([][]byte{certBytes}), nil +} - return certificates, nil +func GetCertificates(certFile string, keyFile string) ([]tls.Certificate, error) { + cert, err := os.ReadFile(certFile) + if err != nil { + log.Fatalf("unable to read cert file %v", err) + return nil, err + } + + key, err := os.ReadFile(keyFile) + if err != nil { + log.Fatalf("unable to read key file %v", err) + return nil, err + } + + return client.LoadServerCertAndKey([]byte(cert), []byte(key), nil) } type CmdTestSuite struct { @@ -64,7 +77,7 @@ type CmdTestSuite struct { } func TestCmdSuite(t *testing.T) { - logger = logger.WithGroup("test-logger") + logger = logger.With(slog.Bool("test-logger", true)) // makes it easy to see which logger is which rootCA, err := GetCACert("docker/tls/config/tls/ca.aerospike.com.crt") if err != nil { t.Fatalf("unable to read root ca %v", err) @@ -72,15 +85,21 @@ func TestCmdSuite(t *testing.T) { logger.Error("Failed to read cert") } - logger.Info("%v", slog.Any("cert", rootCA)) + certificates, err := GetCertificates("docker/mtls/config/tls/localhost.crt", "docker/mtls/config/tls/localhost.key") + if err != nil { + t.Fatalf("unable to read certificates %v", err) + t.FailNow() + logger.Error("Failed to read cert") + } + logger.Info("%v", slog.Any("cert", rootCA)) suite.Run(t, &CmdTestSuite{ - composeFile: "docker/docker-compose.yml", + composeFile: "docker/docker-compose.yml", // vanilla suiteFlags: []string{"--log-level debug"}, avsIP: "localhost", }) suite.Run(t, &CmdTestSuite{ - composeFile: "docker/tls/docker-compose.yml", + composeFile: "docker/tls/docker-compose.yml", // tls suiteFlags: []string{ "--log-level debug", createFlagStr(flags.TLSCaFile, "docker/tls/config/tls/ca.aerospike.com.crt"), @@ -92,7 +111,21 @@ func TestCmdSuite(t *testing.T) { avsIP: "localhost", }) suite.Run(t, &CmdTestSuite{ - composeFile: "docker/auth/docker-compose.yml", + composeFile: "docker/mtls/docker-compose.yml", // mutual tls + suiteFlags: []string{ + "--log-level debug", + createFlagStr(flags.TLSCaFile, "docker/mtls/config/tls/ca.aerospike.com.crt"), + createFlagStr(flags.TLSCertFile, "docker/mtls/config/tls/localhost.crt"), + createFlagStr(flags.TLSKeyFile, "docker/mtls/config/tls/localhost.key"), + }, + avsTLSConfig: &tls.Config{ + Certificates: certificates, + RootCAs: rootCA, + }, + avsIP: "localhost", + }) + suite.Run(t, &CmdTestSuite{ + composeFile: "docker/auth/docker-compose.yml", // tls + auth (auth requires tls) suiteFlags: []string{ "--log-level debug", createFlagStr(flags.TLSCaFile, "docker/auth/config/tls/ca.aerospike.com.crt"),