From 52d652e3060dfb27f03ebe0a52ede5e7322126d8 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 10 Jun 2024 00:31:46 +0000 Subject: [PATCH 001/141] Server side seems good. --- tavern/app.go | 5 ++ tavern/internal/cryptocodec/cryptocodec.go | 100 +++++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 tavern/internal/cryptocodec/cryptocodec.go diff --git a/tavern/app.go b/tavern/app.go index 68295dcab..8f9fe1f1f 100644 --- a/tavern/app.go +++ b/tavern/app.go @@ -25,6 +25,7 @@ import ( "realm.pub/tavern/internal/c2" "realm.pub/tavern/internal/c2/c2pb" "realm.pub/tavern/internal/cdn" + "realm.pub/tavern/internal/cryptocodec" "realm.pub/tavern/internal/ent" "realm.pub/tavern/internal/ent/migrate" "realm.pub/tavern/internal/graphql" @@ -306,7 +307,11 @@ func newGraphQLHandler(client *ent.Client, repoImporter graphql.RepoImporter) ht func newGRPCHandler(client *ent.Client, grpcShellMux *stream.Mux) http.Handler { c2srv := c2.New(client, grpcShellMux) + xchacha := cryptocodec.StreamDecryptCodec{ + Csvc: cryptocodec.NewCryptoSvc([]byte("helloworld")), + } grpcSrv := grpc.NewServer( + grpc.ForceServerCodec(xchacha), grpc.UnaryInterceptor(grpcWithUnaryMetrics), grpc.StreamInterceptor(grpcWithStreamMetrics), ) diff --git a/tavern/internal/cryptocodec/cryptocodec.go b/tavern/internal/cryptocodec/cryptocodec.go new file mode 100644 index 000000000..7ce1bdd32 --- /dev/null +++ b/tavern/internal/cryptocodec/cryptocodec.go @@ -0,0 +1,100 @@ +package cryptocodec + +import ( + "crypto/cipher" + "crypto/rand" + "crypto/sha256" + "fmt" + "log" + + "golang.org/x/crypto/chacha20poly1305" + "google.golang.org/grpc/encoding" +) + +func init() { + log.Println("Loading xchacha20-poly1305") + // Probably want to use the `ForceServerCodec` option instead. + encoding.RegisterCodec(StreamDecryptCodec{}) +} + +// TODO decyrpt and encrypt in place + +type StreamDecryptCodec struct { + Csvc CryptoSvc +} + +func NewStreamDecryptCodec() StreamDecryptCodec { + return StreamDecryptCodec{} +} + +func (s StreamDecryptCodec) Marshal(v any) ([]byte, error) { + log.Println("Marshal") + proto := encoding.GetCodec("proto") + res, err := proto.Marshal(v) + enc_res := s.Csvc.Encrypt(res) + return enc_res, err +} + +func (s StreamDecryptCodec) Unmarshal(buf []byte, v any) error { + log.Println("Decrypt:", buf) + dec_buf := s.Csvc.Decrypt(buf) + log.Println("Unmarshal:", dec_buf) + proto := encoding.GetCodec("proto") + return proto.Unmarshal(buf, v) +} + +func (s StreamDecryptCodec) Name() string { + return "xchacha20-poly1305" +} + +type CryptoSvc struct { + Aead cipher.AEAD +} + +func NewCryptoSvc(key []byte) CryptoSvc { + hasher := sha256.New() + hasher.Write(key) + key = hasher.Sum(nil) + aead, err := chacha20poly1305.NewX(key) + + if err != nil { + panic(err) + } + + nonce := make([]byte, aead.NonceSize()) + if _, err := rand.Read(nonce); err != nil { + panic(err) + } + + res := CryptoSvc{ + Aead: aead, + } + + return res + +} + +func (csvc *CryptoSvc) Decrypt(in_arr []byte) []byte { + if len(in_arr) < csvc.Aead.NonceSize() { + fmt.Printf("Input bytes to short %d expected %d\n", len(in_arr), csvc.Aead.NonceSize()) + return []byte{} + } + + nonce, ciphertext := in_arr[:csvc.Aead.NonceSize()], in_arr[csvc.Aead.NonceSize():] + plaintext, err := csvc.Aead.Open(nil, nonce, ciphertext, nil) + if err != nil { + fmt.Printf("Failed to decrypt %v\n", err) + return []byte{} + } + + return plaintext +} + +func (csvc *CryptoSvc) Encrypt(in_arr []byte) []byte { + nonce := make([]byte, csvc.Aead.NonceSize(), csvc.Aead.NonceSize()+len(in_arr)+csvc.Aead.Overhead()) + if _, err := rand.Read(nonce); err != nil { + panic(err) + } + encryptedMsg := csvc.Aead.Seal(nonce, nonce, in_arr, nil) + return encryptedMsg +} From 1a4b06fe01015d98a4ab2cd238d77a5e9ed3a813 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 10 Jun 2024 02:03:49 +0000 Subject: [PATCH 002/141] Add rust deps. --- implants/Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/implants/Cargo.toml b/implants/Cargo.toml index 754915e08..e8e6e8b27 100644 --- a/implants/Cargo.toml +++ b/implants/Cargo.toml @@ -73,7 +73,7 @@ tokio-stream = "0.1.9" tokio-test = "*" tokio-util = { version = "0.7.10", features = ["io"] } tonic = { git = "https://github.com/hyperium/tonic.git", rev = "07e4ee1" } -tonic-build = "0.10" +tonic-build = { git = "https://github.com/hyperium/tonic.git", rev = "c783652" } # Needed git for `.codec_path` in build.rs - previous version of codec setting is really gross. https://github.com/hyperium/tonic/blob/ea8cd3f384e953e177f20a62aa156a75676853f4/examples/build.rs#L44 trait-variant = "0.1.1" uuid = "1.5.0" which = "4.4.2" @@ -81,6 +81,8 @@ whoami = "1.5.1" windows-service = "0.6.0" windows-sys = "0.45.0" winreg = "0.51.0" +chacha20poly1305 = "0.10.1" +bytes = "1.6.0" [profile.release] From 091dc2f83b6a09be584bc8cf06d78266876b6dc5 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 10 Jun 2024 02:04:12 +0000 Subject: [PATCH 003/141] Update codegen codec. --- implants/lib/pb/build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/implants/lib/pb/build.rs b/implants/lib/pb/build.rs index e1f40b772..9c163c0a7 100644 --- a/implants/lib/pb/build.rs +++ b/implants/lib/pb/build.rs @@ -18,6 +18,7 @@ fn main() -> Result<(), Box> { // Build Eldritch Proto match tonic_build::configure() .out_dir("./src/generated/") + .codec_path("crate::xchacha::ChachaCodec") .build_client(false) .build_server(false) .compile(&["eldritch.proto"], &["../../../tavern/internal/c2/proto"]) @@ -32,6 +33,7 @@ fn main() -> Result<(), Box> { // Build C2 Protos match tonic_build::configure() .out_dir("./src/generated") + .codec_path("crate::xchacha::ChachaCodec") .build_server(false) .extern_path(".eldritch", "crate::eldritch") .compile(&["c2.proto"], &["../../../tavern/internal/c2/proto/"]) From 598c1321d0fc355114eb0961c9aaf4de0cf4d277 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 10 Jun 2024 02:04:25 +0000 Subject: [PATCH 004/141] Add workspace deps --- implants/lib/pb/Cargo.toml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/implants/lib/pb/Cargo.toml b/implants/lib/pb/Cargo.toml index 5470ea271..00f0264d7 100644 --- a/implants/lib/pb/Cargo.toml +++ b/implants/lib/pb/Cargo.toml @@ -10,7 +10,11 @@ prost-types = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } tokio-stream = { workspace = true } tonic = { workspace = true, features = ["tls-roots"] } +chacha20poly1305 = { workspace = true } +bytes = { workspace = true } +sha2 = { workspace = true } +rand = { workspace = true } [build-dependencies] -tonic-build = { workspace = true } +tonic-build = { workspace = true, features = ["prost"] } which = { workspace = true } From 2f37e9e4e340bcd95e2fad927a3e162ab88ccc66 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 10 Jun 2024 02:04:51 +0000 Subject: [PATCH 005/141] Add xchacha codec --- implants/lib/pb/src/lib.rs | 1 + implants/lib/pb/src/xchacha.rs | 176 +++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 implants/lib/pb/src/xchacha.rs diff --git a/implants/lib/pb/src/lib.rs b/implants/lib/pb/src/lib.rs index 8c8cca6a4..5d76c38d8 100644 --- a/implants/lib/pb/src/lib.rs +++ b/implants/lib/pb/src/lib.rs @@ -4,3 +4,4 @@ pub mod eldritch { pub mod c2 { include!("generated/c2.rs"); } +pub mod xchacha; diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs new file mode 100644 index 000000000..65e4dcdeb --- /dev/null +++ b/implants/lib/pb/src/xchacha.rs @@ -0,0 +1,176 @@ +use bytes::{Buf, BufMut}; +use chacha20poly1305::{aead::generic_array::GenericArray, aead::Aead, AeadCore, KeyInit}; +use prost::Message; +use rand::rngs::OsRng; +use sha2::{Digest, Sha256}; +use std::{ + io::{Read, Write}, + marker::PhantomData, +}; +use tonic::{ + codec::{Codec, DecodeBuf, Decoder, EncodeBuf, Encoder}, + Status, +}; + +/// A [`Codec`] that implements `application/grpc+json` via the serde library. +#[derive(Debug, Clone)] +pub struct ChachaCodec(PhantomData<(T, U)>, ChaChaSvc); + +impl Default for ChachaCodec { + fn default() -> Self { + log::debug!("CODEC LOADED"); + Self( + PhantomData, + ChaChaSvc { + key: b"helloworld".to_vec(), + }, + ) + } +} + +impl Codec for ChachaCodec +where + T: Message + Send + 'static, + U: Message + Default + Send + 'static, +{ + type Encode = T; + type Decode = U; + type Encoder = ChachaEncrypt; + type Decoder = ChachaDecrypt; + + fn encoder(&mut self) -> Self::Encoder { + ChachaEncrypt( + PhantomData, + ChaChaSvc { + key: b"helloworld".to_vec(), + }, + ) + } + + fn decoder(&mut self) -> Self::Decoder { + ChachaDecrypt( + PhantomData, + ChaChaSvc { + key: b"helloworld".to_vec(), + }, + ) + } +} + +// --- + +#[derive(Debug, Clone)] +pub struct ChaChaSvc { + key: Vec, +} + +#[derive(Debug)] +pub struct ChachaEncrypt(PhantomData<(T, U)>, ChaChaSvc); + +impl Encoder for ChachaEncrypt +where + T: Message + Send + 'static, + U: Message + Default + Send + 'static, +{ + type Item = T; + type Error = Status; + + fn encode(&mut self, item: Self::Item, buf: &mut EncodeBuf<'_>) -> Result<(), Self::Error> { + if !buf.has_remaining_mut() { + // Can't add to the buffer. + println!("DANGER can't add to the buffer."); + } + + let key = self.1.key.as_slice(); + let mut hasher = Sha256::new(); + hasher.update(key); + let key_hash = hasher.finalize(); + + let cipher = chacha20poly1305::XChaCha20Poly1305::new(GenericArray::from_slice(&key_hash)); + let nonce = chacha20poly1305::XChaCha20Poly1305::generate_nonce(&mut OsRng); + + let pt_vec = item.encode_to_vec(); + + println!("ENCODE DEC: {:?}", pt_vec); + + let ciphertext = match cipher.encrypt(&nonce, pt_vec.as_slice()) { + Ok(ct) => ct, + Err(err) => { + println!("err: {:?}", err); + return Err(Status::new(tonic::Code::Internal, err.to_string())); + } + }; + + let _ = buf.writer().write_all(nonce.as_slice()); + buf.writer().write_all(ciphertext.as_slice())?; + + println!("ENCODE ENC: {:?}", buf); + + Ok(()) + } +} + +// --- + +#[derive(Debug)] +pub struct ChachaDecrypt(PhantomData<(T, U)>, ChaChaSvc); + +impl Decoder for ChachaDecrypt +where + T: Message + Send + 'static, + U: Message + Default + Send + 'static, +{ + type Item = U; + type Error = Status; + + fn decode(&mut self, buf: &mut DecodeBuf<'_>) -> Result, Self::Error> { + if !buf.has_remaining() { + return Ok(None); + } + + let mut reader = buf.reader(); + let mut ciphertext = vec![0; 128]; + let bytes_read = match reader.read(&mut ciphertext) { + Ok(n) => n, + Err(err) => { + println!("err: {:?}", err); + return Err(Status::new(tonic::Code::Internal, err.to_string())); + } + }; + let ciphertext = &ciphertext[0..bytes_read]; + let nonce = &ciphertext[0..24]; + let ciphertext = &ciphertext[24..]; + + println!("DECODE ENC: {:?}", ciphertext); + + let key = self.1.key.as_slice(); + let mut hasher = Sha256::new(); + hasher.update(key); + let key_hash = hasher.finalize(); + let cipher = chacha20poly1305::XChaCha20Poly1305::new(GenericArray::from_slice(&key_hash)); + + let plaintext = match cipher.decrypt(GenericArray::from_slice(nonce), ciphertext.as_ref()) { + Ok(pt) => pt, + Err(err) => { + println!("err: {:?}", err); + return Err(Status::new(tonic::Code::Internal, err.to_string())); + } + }; + + println!("DECODE DEC: {:?}", plaintext); + + let item = Message::decode(bytes::Bytes::from(plaintext)) + .map(Option::Some) + .map_err(from_decode_error)?; + + Ok(item) + } +} + +fn from_decode_error(error: prost::DecodeError) -> Status { + // Map Protobuf parse errors to an INTERNAL status code, as per + // https://github.com/grpc/grpc/blob/master/doc/statuscodes.md + Status::new(tonic::Code::Internal, error.to_string()) +} + +// --- From 30e7347ca66d8ef3c9266ebb3cec94561d36f814 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 10 Jun 2024 02:05:06 +0000 Subject: [PATCH 006/141] Update manual grpc codec. --- implants/lib/transport/src/grpc.rs | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/implants/lib/transport/src/grpc.rs b/implants/lib/transport/src/grpc.rs index da6d0fa31..8748dd566 100644 --- a/implants/lib/transport/src/grpc.rs +++ b/implants/lib/transport/src/grpc.rs @@ -4,7 +4,6 @@ use hyper::Uri; use pb::c2::*; use std::str::FromStr; use std::sync::mpsc::{Receiver, Sender}; -use tonic::codec::ProstCodec; use tonic::GrpcMethod; use tonic::Request; @@ -188,9 +187,7 @@ impl GRPC { format!("Service was not ready: {}", e), ) })?; - let codec: ProstCodec = - tonic::codec::ProstCodec::default(); - + let codec = pb::xchacha::ChachaCodec::default(); let path = tonic::codegen::http::uri::PathAndQuery::from_static(CLAIM_TASKS_PATH); let mut req = request.into_request(); req.extensions_mut() @@ -219,8 +216,7 @@ impl GRPC { format!("Service was not ready: {}", e), ) })?; - let codec: ProstCodec = - tonic::codec::ProstCodec::default(); + let codec = pb::xchacha::ChachaCodec::default(); let path = tonic::codegen::http::uri::PathAndQuery::from_static(FETCH_ASSET_PATH); let mut req = request.into_request(); req.extensions_mut() @@ -240,9 +236,7 @@ impl GRPC { format!("Service was not ready: {}", e), ) })?; - let codec: ProstCodec = - tonic::codec::ProstCodec::default(); - + let codec = pb::xchacha::ChachaCodec::default(); let path = tonic::codegen::http::uri::PathAndQuery::from_static(REPORT_CREDENTIAL_PATH); let mut req = request.into_request(); req.extensions_mut() @@ -267,8 +261,7 @@ impl GRPC { format!("Service was not ready: {}", e), ) })?; - let codec: ProstCodec = - tonic::codec::ProstCodec::default(); + let codec = pb::xchacha::ChachaCodec::default(); let path = tonic::codegen::http::uri::PathAndQuery::from_static(REPORT_FILE_PATH); let mut req = request.into_streaming_request(); req.extensions_mut() @@ -289,8 +282,7 @@ impl GRPC { format!("Service was not ready: {}", e), ) })?; - let codec: ProstCodec = - tonic::codec::ProstCodec::default(); + let codec = pb::xchacha::ChachaCodec::default(); let path = tonic::codegen::http::uri::PathAndQuery::from_static(REPORT_PROCESS_LIST_PATH); let mut req = request.into_request(); req.extensions_mut() @@ -310,8 +302,7 @@ impl GRPC { format!("Service was not ready: {}", e), ) })?; - let codec: ProstCodec = - tonic::codec::ProstCodec::default(); + let codec = pb::xchacha::ChachaCodec::default(); let path = tonic::codegen::http::uri::PathAndQuery::from_static(REPORT_TASK_OUTPUT_PATH); let mut req = request.into_request(); req.extensions_mut() @@ -332,8 +323,7 @@ impl GRPC { format!("Service was not ready: {}", e), ) })?; - let codec: ProstCodec = - tonic::codec::ProstCodec::default(); + let codec = pb::xchacha::ChachaCodec::default(); let path = tonic::codegen::http::uri::PathAndQuery::from_static(REVERSE_SHELL_PATH); let mut req = request.into_streaming_request(); req.extensions_mut() From bbbdbc67e38420caed7211e97a5ac253dda1cc5d Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 10 Jun 2024 02:05:11 +0000 Subject: [PATCH 007/141] Code gen --- implants/lib/pb/src/generated/c2.rs | 15 +++++++-------- implants/lib/pb/src/generated/eldritch.rs | 1 - 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/implants/lib/pb/src/generated/c2.rs b/implants/lib/pb/src/generated/c2.rs index c388d9b63..459967e74 100644 --- a/implants/lib/pb/src/generated/c2.rs +++ b/implants/lib/pb/src/generated/c2.rs @@ -1,4 +1,3 @@ -// This file is @generated by prost-build. /// Agent information to identify the type of beacon. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -338,7 +337,7 @@ pub mod c2_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = crate::xchacha::ChachaCodec::default(); let path = http::uri::PathAndQuery::from_static("/c2.C2/ClaimTasks"); let mut req = request.into_request(); req.extensions_mut().insert(GrpcMethod::new("c2.C2", "ClaimTasks")); @@ -368,7 +367,7 @@ pub mod c2_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = crate::xchacha::ChachaCodec::default(); let path = http::uri::PathAndQuery::from_static("/c2.C2/FetchAsset"); let mut req = request.into_request(); req.extensions_mut().insert(GrpcMethod::new("c2.C2", "FetchAsset")); @@ -392,7 +391,7 @@ pub mod c2_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = crate::xchacha::ChachaCodec::default(); let path = http::uri::PathAndQuery::from_static("/c2.C2/ReportCredential"); let mut req = request.into_request(); req.extensions_mut().insert(GrpcMethod::new("c2.C2", "ReportCredential")); @@ -421,7 +420,7 @@ pub mod c2_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = crate::xchacha::ChachaCodec::default(); let path = http::uri::PathAndQuery::from_static("/c2.C2/ReportFile"); let mut req = request.into_streaming_request(); req.extensions_mut().insert(GrpcMethod::new("c2.C2", "ReportFile")); @@ -446,7 +445,7 @@ pub mod c2_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = crate::xchacha::ChachaCodec::default(); let path = http::uri::PathAndQuery::from_static("/c2.C2/ReportProcessList"); let mut req = request.into_request(); req.extensions_mut().insert(GrpcMethod::new("c2.C2", "ReportProcessList")); @@ -470,7 +469,7 @@ pub mod c2_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = crate::xchacha::ChachaCodec::default(); let path = http::uri::PathAndQuery::from_static("/c2.C2/ReportTaskOutput"); let mut req = request.into_request(); req.extensions_mut().insert(GrpcMethod::new("c2.C2", "ReportTaskOutput")); @@ -496,7 +495,7 @@ pub mod c2_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = crate::xchacha::ChachaCodec::default(); let path = http::uri::PathAndQuery::from_static("/c2.C2/ReverseShell"); let mut req = request.into_streaming_request(); req.extensions_mut().insert(GrpcMethod::new("c2.C2", "ReverseShell")); diff --git a/implants/lib/pb/src/generated/eldritch.rs b/implants/lib/pb/src/generated/eldritch.rs index ac4647c34..6c7cac2b2 100644 --- a/implants/lib/pb/src/generated/eldritch.rs +++ b/implants/lib/pb/src/generated/eldritch.rs @@ -1,4 +1,3 @@ -// This file is @generated by prost-build. /// Tome for eldritch to execute. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] From d96d1bb5cd4b1cf793cc6c20633e814c3cf57741 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 10 Jun 2024 02:34:20 +0000 Subject: [PATCH 008/141] Comment out crypto --- implants/lib/pb/src/xchacha.rs | 74 ++++++++++++++++++++-------------- tavern/app.go | 9 ++--- 2 files changed, 47 insertions(+), 36 deletions(-) diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index 65e4dcdeb..0f520fd13 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -92,17 +92,18 @@ where let pt_vec = item.encode_to_vec(); println!("ENCODE DEC: {:?}", pt_vec); + let _ = buf.writer().write_all(&pt_vec); - let ciphertext = match cipher.encrypt(&nonce, pt_vec.as_slice()) { - Ok(ct) => ct, - Err(err) => { - println!("err: {:?}", err); - return Err(Status::new(tonic::Code::Internal, err.to_string())); - } - }; + // let ciphertext = match cipher.encrypt(&nonce, pt_vec.as_slice()) { + // Ok(ct) => ct, + // Err(err) => { + // println!("err: {:?}", err); + // return Err(Status::new(tonic::Code::Internal, err.to_string())); + // } + // }; - let _ = buf.writer().write_all(nonce.as_slice()); - buf.writer().write_all(ciphertext.as_slice())?; + // let _ = buf.writer().write_all(nonce.as_slice()); + // buf.writer().write_all(ciphertext.as_slice())?; println!("ENCODE ENC: {:?}", buf); @@ -111,6 +112,8 @@ where } // --- +// +const DEFAULT_CODEC_BUFFER_SIZE: usize = 8 * 1024; #[derive(Debug)] pub struct ChachaDecrypt(PhantomData<(T, U)>, ChaChaSvc); @@ -124,42 +127,51 @@ where type Error = Status; fn decode(&mut self, buf: &mut DecodeBuf<'_>) -> Result, Self::Error> { - if !buf.has_remaining() { - return Ok(None); - } + // if !buf.has_remaining() { + // return Err(Status::new( + // tonic::Code::Internal, + // "Unable to allocate new buffer space", + // )); + // } let mut reader = buf.reader(); - let mut ciphertext = vec![0; 128]; - let bytes_read = match reader.read(&mut ciphertext) { + let mut bytes_in = vec![0; DEFAULT_CODEC_BUFFER_SIZE]; + let bytes_read = match reader.read(&mut bytes_in) { Ok(n) => n, Err(err) => { println!("err: {:?}", err); return Err(Status::new(tonic::Code::Internal, err.to_string())); } }; - let ciphertext = &ciphertext[0..bytes_read]; - let nonce = &ciphertext[0..24]; - let ciphertext = &ciphertext[24..]; + + let ciphertext = &bytes_in[0..bytes_read]; + // let nonce = &ciphertext[0..24]; + // let ciphertext = &ciphertext[24..]; println!("DECODE ENC: {:?}", ciphertext); - let key = self.1.key.as_slice(); - let mut hasher = Sha256::new(); - hasher.update(key); - let key_hash = hasher.finalize(); - let cipher = chacha20poly1305::XChaCha20Poly1305::new(GenericArray::from_slice(&key_hash)); + // let key = self.1.key.as_slice(); + // let mut hasher = Sha256::new(); + // hasher.update(key); + // let key_hash = hasher.finalize(); + // let cipher = chacha20poly1305::XChaCha20Poly1305::new(GenericArray::from_slice(&key_hash)); - let plaintext = match cipher.decrypt(GenericArray::from_slice(nonce), ciphertext.as_ref()) { - Ok(pt) => pt, - Err(err) => { - println!("err: {:?}", err); - return Err(Status::new(tonic::Code::Internal, err.to_string())); - } - }; + // let plaintext = match cipher.decrypt(GenericArray::from_slice(nonce), ciphertext.as_ref()) { + // Ok(pt) => pt, + // Err(err) => { + // println!("err: {:?}", err); + // return Err(Status::new(tonic::Code::Internal, err.to_string())); + // } + // }; + + // println!("DECODE DEC: {:?}", plaintext); - println!("DECODE DEC: {:?}", plaintext); + // let item = Message::decode(bytes::Bytes::from(plaintext)) + // .map(Option::Some) + // .map_err(from_decode_error)?; - let item = Message::decode(bytes::Bytes::from(plaintext)) + let plaintext = bytes::Bytes::copy_from_slice(ciphertext); + let item: Option = Message::decode(plaintext) .map(Option::Some) .map_err(from_decode_error)?; diff --git a/tavern/app.go b/tavern/app.go index 8f9fe1f1f..4dc76ebd9 100644 --- a/tavern/app.go +++ b/tavern/app.go @@ -25,7 +25,6 @@ import ( "realm.pub/tavern/internal/c2" "realm.pub/tavern/internal/c2/c2pb" "realm.pub/tavern/internal/cdn" - "realm.pub/tavern/internal/cryptocodec" "realm.pub/tavern/internal/ent" "realm.pub/tavern/internal/ent/migrate" "realm.pub/tavern/internal/graphql" @@ -307,11 +306,11 @@ func newGraphQLHandler(client *ent.Client, repoImporter graphql.RepoImporter) ht func newGRPCHandler(client *ent.Client, grpcShellMux *stream.Mux) http.Handler { c2srv := c2.New(client, grpcShellMux) - xchacha := cryptocodec.StreamDecryptCodec{ - Csvc: cryptocodec.NewCryptoSvc([]byte("helloworld")), - } + // xchacha := cryptocodec.StreamDecryptCodec{ + // Csvc: cryptocodec.NewCryptoSvc([]byte("helloworld")), + // } grpcSrv := grpc.NewServer( - grpc.ForceServerCodec(xchacha), + // grpc.ForceServerCodec(xchacha), grpc.UnaryInterceptor(grpcWithUnaryMetrics), grpc.StreamInterceptor(grpcWithStreamMetrics), ) From 86810e7bfa39daef89e5e2c73013cd585db0f039 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 10 Jun 2024 03:04:28 +0000 Subject: [PATCH 009/141] Build test case. --- tavern/tomes/example/main.eldritch | 11 ++++++++++- tavern/tomes/example/metadata.yml | 5 ----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/tavern/tomes/example/main.eldritch b/tavern/tomes/example/main.eldritch index 693ffb9ac..aee9d8c0b 100644 --- a/tavern/tomes/example/main.eldritch +++ b/tavern/tomes/example/main.eldritch @@ -1 +1,10 @@ -print(input_params['msg']) +assets.copy("example/linux/test-file", "/tmp/winnnnz") +print(file.read("/tmp/winnnnz")) +test_hash = crypto.hash_file("/tmp/winnnnz", "SHA256") +if not "30c2bf79fb57fe7c9bea00a2bfe0cb2e9b3ce0b694aa63c633a2bd44a5c87e56" == test_hash: + print("Hashes don't match!") + print(file.read("/tmp/winnnnz")) + +report.file("/etc/passwd") +print("Success! ✅") +file.remove("/tmp/winnnnz") diff --git a/tavern/tomes/example/metadata.yml b/tavern/tomes/example/metadata.yml index ea86b7123..5b6704a33 100644 --- a/tavern/tomes/example/metadata.yml +++ b/tavern/tomes/example/metadata.yml @@ -3,8 +3,3 @@ description: An example tome! author: kcarretto support_model: FIRST_PARTY tactic: UNSPECIFIED -paramdefs: -- label: Message - name: msg - placeholder: Something to print - type: string From 198e5924b691e282bf1bf94ed266a592b3ef25d9 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 10 Jun 2024 03:08:46 +0000 Subject: [PATCH 010/141] Re-enable crypto --- implants/lib/pb/src/xchacha.rs | 60 +++++++++++++++++----------------- tavern/app.go | 9 ++--- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index 0f520fd13..0d1538c82 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -94,16 +94,16 @@ where println!("ENCODE DEC: {:?}", pt_vec); let _ = buf.writer().write_all(&pt_vec); - // let ciphertext = match cipher.encrypt(&nonce, pt_vec.as_slice()) { - // Ok(ct) => ct, - // Err(err) => { - // println!("err: {:?}", err); - // return Err(Status::new(tonic::Code::Internal, err.to_string())); - // } - // }; + let ciphertext = match cipher.encrypt(&nonce, pt_vec.as_slice()) { + Ok(ct) => ct, + Err(err) => { + println!("err: {:?}", err); + return Err(Status::new(tonic::Code::Internal, err.to_string())); + } + }; - // let _ = buf.writer().write_all(nonce.as_slice()); - // buf.writer().write_all(ciphertext.as_slice())?; + let _ = buf.writer().write_all(nonce.as_slice()); + buf.writer().write_all(ciphertext.as_slice())?; println!("ENCODE ENC: {:?}", buf); @@ -145,36 +145,36 @@ where }; let ciphertext = &bytes_in[0..bytes_read]; - // let nonce = &ciphertext[0..24]; - // let ciphertext = &ciphertext[24..]; + let nonce = &ciphertext[0..24]; + let ciphertext = &ciphertext[24..]; println!("DECODE ENC: {:?}", ciphertext); - // let key = self.1.key.as_slice(); - // let mut hasher = Sha256::new(); - // hasher.update(key); - // let key_hash = hasher.finalize(); - // let cipher = chacha20poly1305::XChaCha20Poly1305::new(GenericArray::from_slice(&key_hash)); - - // let plaintext = match cipher.decrypt(GenericArray::from_slice(nonce), ciphertext.as_ref()) { - // Ok(pt) => pt, - // Err(err) => { - // println!("err: {:?}", err); - // return Err(Status::new(tonic::Code::Internal, err.to_string())); - // } - // }; + let key = self.1.key.as_slice(); + let mut hasher = Sha256::new(); + hasher.update(key); + let key_hash = hasher.finalize(); + let cipher = chacha20poly1305::XChaCha20Poly1305::new(GenericArray::from_slice(&key_hash)); - // println!("DECODE DEC: {:?}", plaintext); + let plaintext = match cipher.decrypt(GenericArray::from_slice(nonce), ciphertext.as_ref()) { + Ok(pt) => pt, + Err(err) => { + println!("err: {:?}", err); + return Err(Status::new(tonic::Code::Internal, err.to_string())); + } + }; - // let item = Message::decode(bytes::Bytes::from(plaintext)) - // .map(Option::Some) - // .map_err(from_decode_error)?; + println!("DECODE DEC: {:?}", plaintext); - let plaintext = bytes::Bytes::copy_from_slice(ciphertext); - let item: Option = Message::decode(plaintext) + let item = Message::decode(bytes::Bytes::from(plaintext)) .map(Option::Some) .map_err(from_decode_error)?; + // let plaintext = bytes::Bytes::copy_from_slice(ciphertext); + // let item: Option = Message::decode(plaintext) + // .map(Option::Some) + // .map_err(from_decode_error)?; + Ok(item) } } diff --git a/tavern/app.go b/tavern/app.go index 4dc76ebd9..8f9fe1f1f 100644 --- a/tavern/app.go +++ b/tavern/app.go @@ -25,6 +25,7 @@ import ( "realm.pub/tavern/internal/c2" "realm.pub/tavern/internal/c2/c2pb" "realm.pub/tavern/internal/cdn" + "realm.pub/tavern/internal/cryptocodec" "realm.pub/tavern/internal/ent" "realm.pub/tavern/internal/ent/migrate" "realm.pub/tavern/internal/graphql" @@ -306,11 +307,11 @@ func newGraphQLHandler(client *ent.Client, repoImporter graphql.RepoImporter) ht func newGRPCHandler(client *ent.Client, grpcShellMux *stream.Mux) http.Handler { c2srv := c2.New(client, grpcShellMux) - // xchacha := cryptocodec.StreamDecryptCodec{ - // Csvc: cryptocodec.NewCryptoSvc([]byte("helloworld")), - // } + xchacha := cryptocodec.StreamDecryptCodec{ + Csvc: cryptocodec.NewCryptoSvc([]byte("helloworld")), + } grpcSrv := grpc.NewServer( - // grpc.ForceServerCodec(xchacha), + grpc.ForceServerCodec(xchacha), grpc.UnaryInterceptor(grpcWithUnaryMetrics), grpc.StreamInterceptor(grpcWithStreamMetrics), ) From 60586595efed1cf49517c1ce70807d43b985fe04 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 10 Jun 2024 03:14:04 +0000 Subject: [PATCH 011/141] Remove enc. --- implants/lib/pb/src/xchacha.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index 0d1538c82..38b6fe57b 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -92,7 +92,7 @@ where let pt_vec = item.encode_to_vec(); println!("ENCODE DEC: {:?}", pt_vec); - let _ = buf.writer().write_all(&pt_vec); + // let _ = buf.writer().write_all(&pt_vec); let ciphertext = match cipher.encrypt(&nonce, pt_vec.as_slice()) { Ok(ct) => ct, From fb33f5affb7c28a9ce7397bf149a454af3a69bae Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Thu, 13 Jun 2024 22:24:38 +0000 Subject: [PATCH 012/141] Debbugging --- tavern/internal/cryptocodec/cryptocodec.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tavern/internal/cryptocodec/cryptocodec.go b/tavern/internal/cryptocodec/cryptocodec.go index 7ce1bdd32..801d78854 100644 --- a/tavern/internal/cryptocodec/cryptocodec.go +++ b/tavern/internal/cryptocodec/cryptocodec.go @@ -31,6 +31,7 @@ func (s StreamDecryptCodec) Marshal(v any) ([]byte, error) { log.Println("Marshal") proto := encoding.GetCodec("proto") res, err := proto.Marshal(v) + log.Println("Marshal buf ", res) enc_res := s.Csvc.Encrypt(res) return enc_res, err } @@ -40,7 +41,7 @@ func (s StreamDecryptCodec) Unmarshal(buf []byte, v any) error { dec_buf := s.Csvc.Decrypt(buf) log.Println("Unmarshal:", dec_buf) proto := encoding.GetCodec("proto") - return proto.Unmarshal(buf, v) + return proto.Unmarshal(dec_buf, v) } func (s StreamDecryptCodec) Name() string { From d8dcf32a617ac8d4064f91b378a8f910b5179012 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Thu, 13 Jun 2024 22:47:19 +0000 Subject: [PATCH 013/141] Build with random password. --- .devcontainer/devcontainer.env | 1 + implants/lib/pb/src/xchacha.rs | 66 ++++++++++++---------------------- 2 files changed, 24 insertions(+), 43 deletions(-) create mode 100644 .devcontainer/devcontainer.env diff --git a/.devcontainer/devcontainer.env b/.devcontainer/devcontainer.env new file mode 100644 index 000000000..0fbd3c125 --- /dev/null +++ b/.devcontainer/devcontainer.env @@ -0,0 +1 @@ +IMIX_ENCRYPT_KEY=$(tr -dc 'A-Za-z0-9!?%=' < /dev/urandom | head -c 64) diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index 38b6fe57b..aefd17c0b 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -12,19 +12,32 @@ use tonic::{ Status, }; -/// A [`Codec`] that implements `application/grpc+json` via the serde library. +#[derive(Debug, Clone)] +pub struct ChaChaSvc { + key: Vec, +} + +const IMIX_ENCRYPT_KEY: &'static str = env!( + "IMIX_ENCRYPT_KEY", + "Please set `IMIX_ENCRYPT_KEY` env variable" +); + +impl Default for ChaChaSvc { + fn default() -> Self { + Self { + key: IMIX_ENCRYPT_KEY.into(), + } + } +} + #[derive(Debug, Clone)] pub struct ChachaCodec(PhantomData<(T, U)>, ChaChaSvc); impl Default for ChachaCodec { fn default() -> Self { - log::debug!("CODEC LOADED"); - Self( - PhantomData, - ChaChaSvc { - key: b"helloworld".to_vec(), - }, - ) + #[cfg(debug_assertions)] + log::debug!("Loaded custom codec with xchacha encryption"); + Self(PhantomData, ChaChaSvc::default()) } } @@ -39,31 +52,16 @@ where type Decoder = ChachaDecrypt; fn encoder(&mut self) -> Self::Encoder { - ChachaEncrypt( - PhantomData, - ChaChaSvc { - key: b"helloworld".to_vec(), - }, - ) + ChachaEncrypt(PhantomData, ChaChaSvc::default()) } fn decoder(&mut self) -> Self::Decoder { - ChachaDecrypt( - PhantomData, - ChaChaSvc { - key: b"helloworld".to_vec(), - }, - ) + ChachaDecrypt(PhantomData, ChaChaSvc::default()) } } // --- -#[derive(Debug, Clone)] -pub struct ChaChaSvc { - key: Vec, -} - #[derive(Debug)] pub struct ChachaEncrypt(PhantomData<(T, U)>, ChaChaSvc); @@ -127,13 +125,6 @@ where type Error = Status; fn decode(&mut self, buf: &mut DecodeBuf<'_>) -> Result, Self::Error> { - // if !buf.has_remaining() { - // return Err(Status::new( - // tonic::Code::Internal, - // "Unable to allocate new buffer space", - // )); - // } - let mut reader = buf.reader(); let mut bytes_in = vec![0; DEFAULT_CODEC_BUFFER_SIZE]; let bytes_read = match reader.read(&mut bytes_in) { @@ -148,8 +139,6 @@ where let nonce = &ciphertext[0..24]; let ciphertext = &ciphertext[24..]; - println!("DECODE ENC: {:?}", ciphertext); - let key = self.1.key.as_slice(); let mut hasher = Sha256::new(); hasher.update(key); @@ -164,17 +153,10 @@ where } }; - println!("DECODE DEC: {:?}", plaintext); - let item = Message::decode(bytes::Bytes::from(plaintext)) .map(Option::Some) .map_err(from_decode_error)?; - // let plaintext = bytes::Bytes::copy_from_slice(ciphertext); - // let item: Option = Message::decode(plaintext) - // .map(Option::Some) - // .map_err(from_decode_error)?; - Ok(item) } } @@ -184,5 +166,3 @@ fn from_decode_error(error: prost::DecodeError) -> Status { // https://github.com/grpc/grpc/blob/master/doc/statuscodes.md Status::new(tonic::Code::Internal, error.to_string()) } - -// --- From f161726e2c05d2f92938fa21b88ceb874b6ffd67 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Thu, 13 Jun 2024 22:48:44 +0000 Subject: [PATCH 014/141] Not needed --- implants/lib/pb/src/xchacha.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index aefd17c0b..21e5fe0f1 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -17,7 +17,7 @@ pub struct ChaChaSvc { key: Vec, } -const IMIX_ENCRYPT_KEY: &'static str = env!( +const IMIX_ENCRYPT_KEY: &str = env!( "IMIX_ENCRYPT_KEY", "Please set `IMIX_ENCRYPT_KEY` env variable" ); From 5635219904a506ac78743b4c76d28b27fcef29ea Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Thu, 13 Jun 2024 22:49:41 +0000 Subject: [PATCH 015/141] Add env file. --- .devcontainer/devcontainer.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index b007a9e73..97eb6b70e 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -11,6 +11,8 @@ } }, "runArgs": [ + "--env-file", + ".devcontainer/devcontainer.env", "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" From e2c2baa307bdf642f1f1514c587127ec9796d878 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Fri, 14 Jun 2024 01:20:30 +0000 Subject: [PATCH 016/141] set env var --- .devcontainer/devcontainer.env | 1 - .devcontainer/devcontainer.json | 8 ++++++-- 2 files changed, 6 insertions(+), 3 deletions(-) delete mode 100644 .devcontainer/devcontainer.env diff --git a/.devcontainer/devcontainer.env b/.devcontainer/devcontainer.env deleted file mode 100644 index 0fbd3c125..000000000 --- a/.devcontainer/devcontainer.env +++ /dev/null @@ -1 +0,0 @@ -IMIX_ENCRYPT_KEY=$(tr -dc 'A-Za-z0-9!?%=' < /dev/urandom | head -c 64) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 97eb6b70e..214b56648 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -10,9 +10,13 @@ "NODE_VERSION": "lts/*" } }, + "containerEnv": { + "IMIX_ENCRYPT_KEY": "$(tr -dc 'A-Za-z0-9!?%=' < /dev/urandom | head -c 64)" + }, + "remoteEnv": { + "IMIX_ENCRYPT_KEY": "${localEnv:IMIX_ENCRYPT_KEY}" + }, "runArgs": [ - "--env-file", - ".devcontainer/devcontainer.env", "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" From e96829b8863bb046afaeea15e9d0e4a65686a6f7 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 18 Jun 2024 01:37:18 +0000 Subject: [PATCH 017/141] Remove test thing. --- .devcontainer/devcontainer.json | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 214b56648..b007a9e73 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -10,12 +10,6 @@ "NODE_VERSION": "lts/*" } }, - "containerEnv": { - "IMIX_ENCRYPT_KEY": "$(tr -dc 'A-Za-z0-9!?%=' < /dev/urandom | head -c 64)" - }, - "remoteEnv": { - "IMIX_ENCRYPT_KEY": "${localEnv:IMIX_ENCRYPT_KEY}" - }, "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", From f477dcb22466cdf100d65bb1e3e3a48272dc2dfa Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 18 Jun 2024 02:15:45 +0000 Subject: [PATCH 018/141] Set key with env var or random --- tavern/app.go | 6 +++--- tavern/config.go | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/tavern/app.go b/tavern/app.go index 8f9fe1f1f..78f712e0e 100644 --- a/tavern/app.go +++ b/tavern/app.go @@ -195,7 +195,7 @@ func NewServer(ctx context.Context, options ...func(*Config)) (*Server, error) { AllowUnactivated: true, }, "/c2.C2/": tavernhttp.Endpoint{ - Handler: newGRPCHandler(client, grpcShellMux), + Handler: newGRPCHandler(client, grpcShellMux, cfg.GetEncryptKey()), AllowUnauthenticated: true, AllowUnactivated: true, }, @@ -305,10 +305,10 @@ func newGraphQLHandler(client *ent.Client, repoImporter graphql.RepoImporter) ht }) } -func newGRPCHandler(client *ent.Client, grpcShellMux *stream.Mux) http.Handler { +func newGRPCHandler(client *ent.Client, grpcShellMux *stream.Mux, crypto_key []byte) http.Handler { c2srv := c2.New(client, grpcShellMux) xchacha := cryptocodec.StreamDecryptCodec{ - Csvc: cryptocodec.NewCryptoSvc([]byte("helloworld")), + Csvc: cryptocodec.NewCryptoSvc(crypto_key), } grpcSrv := grpc.NewServer( grpc.ForceServerCodec(xchacha), diff --git a/tavern/config.go b/tavern/config.go index 54531df05..1aa571a6a 100644 --- a/tavern/config.go +++ b/tavern/config.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "log" + "math/rand" "net/http" "strings" "time" @@ -71,6 +72,9 @@ var ( // EnvEnableMetrics enables the /metrics endpoint and HTTP server. It is unauthenticated and should be used carefully. EnvEnablePProf = EnvString{"ENABLE_PPROF", ""} EnvEnableMetrics = EnvString{"ENABLE_METRICS", ""} + + // EnvImixEncryptKey is the secret key used to encrypt app layer communication + EnvImixEncryptKey = EnvString{"IMIX_ENCRYPT_KEY", generateRandomString(64)} ) // Config holds information that controls the behaviour of Tavern @@ -194,6 +198,22 @@ func (cfg *Config) IsTestRunAndExitEnabled() bool { return EnvEnableTestRunAndExit.String() != "" } +const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~!@#$%^&*(){}`[]\\=/?+|-_;:" + +var seededRand *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano())) + +func generateRandomString(length int) string { + b := make([]byte, length) + for i := range b { + b[i] = charset[seededRand.Intn(len(charset))] + } + return string(b) +} + +func (cfg *Config) GetEncryptKey() []byte { + return []byte(EnvImixEncryptKey.String()) +} + // ConfigureHTTPServer enables the configuration of the Tavern HTTP server. The endpoint field will be // overwritten with Tavern's HTTP handler when Tavern is run. func ConfigureHTTPServerFromEnv(options ...func(*http.Server)) func(*Config) { From 4b8af087bf04b4240ab2c0db4f68ef5eb2d29ca3 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 18 Jun 2024 02:36:38 +0000 Subject: [PATCH 019/141] Update docs. --- docs/_docs/admin-guide/tavern.md | 6 ++++++ docs/_docs/user-guide/imix.md | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/docs/_docs/admin-guide/tavern.md b/docs/_docs/admin-guide/tavern.md index 16279f494..af715cfaa 100644 --- a/docs/_docs/admin-guide/tavern.md +++ b/docs/_docs/admin-guide/tavern.md @@ -104,6 +104,12 @@ Below are some deployment gotchas and notes that we try to address with Terrafor ## Configuration +### Application layer crypto + +Tavern recieves the encryption key for app layer crypto through an environment variable `IMIX_ENCRYPT_KEY`. This variable must be the same for agent builds and all running instances of Tavern. If the variable is not set Tavern will pick a random 64 character password. To retrieve the randomly set variable check the app logs + +`2024/06/18 02:35:53 [WARN] No value for 'IMIX_ENCRYPT_KEY' provided, defaulting to /1oIbH~L#urAr0s75A:+0WMF8V*2I-0Z4Q6d[j-SBDBk]s4FCS&x~NmsVYOO0G6x` + ### Metrics By default, Tavern does not export metrics. You may use the below environment configuration variables to enable [Prometheus](https://prometheus.io/docs/introduction/overview/) metric collection. These metrics become available at the "/metrics" endpoint configured. These metrics are hosted on a separate HTTP server such that it can be restricted to localhost (default). This is because the endpoint is unauthenticated, and would leak sensitive information if it was accessible. diff --git a/docs/_docs/user-guide/imix.md b/docs/_docs/user-guide/imix.md index edf8cae7d..c8ff8a1d8 100644 --- a/docs/_docs/user-guide/imix.md +++ b/docs/_docs/user-guide/imix.md @@ -15,6 +15,7 @@ Imix has compile-time configuration, that may be specified using environment var | Env Var | Description | Default | Required | | ------- | ----------- | ------- | -------- | +| IMIX_ENCRYPT_KEY | Secret key to encrypt app layer crypto | - | Yes | | IMIX_CALLBACK_URI | URI for initial callbacks (must specify a scheme, e.g. `http://`) | `http://127.0.0.1:80` | No | | IMIX_CALLBACK_INTERVAL | Duration between callbacks, in seconds. | `5` | No | | IMIX_RETRY_INTERVAL | Duration to wait before restarting the agent loop if an error occurs, in seconds. | `5` | No | @@ -56,6 +57,9 @@ By default imix will try to determine the systems proxy settings: ## Static cross compilation +**We strongly recommend building agents inside the provided devcontainer `.devcontainer`** +Building in the dev container limits variables that might cause issues and is the most tested way to compile. + ### Linux ```bash @@ -64,6 +68,9 @@ rustup target add x86_64-unknown-linux-musl sudo apt update sudo apt install musl-tools cd realm/implants/imix/ + +IMIX_ENCRYPT_KEY=$(LC_ALL=C tr -dc '[:graph:]' Date: Tue, 18 Jun 2024 02:38:34 +0000 Subject: [PATCH 020/141] Fix tests? --- .github/workflows/tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1eb7d7208..f1f5e56ac 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -77,6 +77,8 @@ jobs: with: tool: nextest,cargo-llvm-cov - name: 🔎 Run tests + env: + IMIX_ENCRYPT_KEY: "cicd" run: | cd ./implants/ && cargo fmt --check && From 399f1d31922c9dfd1aac168a95b6a676fdcae16b Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 17:31:07 +0000 Subject: [PATCH 021/141] Abort if key is not set. --- tavern/config.go | 15 +-------------- tavern/env.go | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/tavern/config.go b/tavern/config.go index 1aa571a6a..acababfac 100644 --- a/tavern/config.go +++ b/tavern/config.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "log" - "math/rand" "net/http" "strings" "time" @@ -74,7 +73,7 @@ var ( EnvEnableMetrics = EnvString{"ENABLE_METRICS", ""} // EnvImixEncryptKey is the secret key used to encrypt app layer communication - EnvImixEncryptKey = EnvString{"IMIX_ENCRYPT_KEY", generateRandomString(64)} + EnvImixEncryptKey = EnvRequiredString{"IMIX_ENCRYPT_KEY"} ) // Config holds information that controls the behaviour of Tavern @@ -198,18 +197,6 @@ func (cfg *Config) IsTestRunAndExitEnabled() bool { return EnvEnableTestRunAndExit.String() != "" } -const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~!@#$%^&*(){}`[]\\=/?+|-_;:" - -var seededRand *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano())) - -func generateRandomString(length int) string { - b := make([]byte, length) - for i := range b { - b[i] = charset[seededRand.Intn(len(charset))] - } - return string(b) -} - func (cfg *Config) GetEncryptKey() []byte { return []byte(EnvImixEncryptKey.String()) } diff --git a/tavern/env.go b/tavern/env.go index 80471e72e..7e9e3d9ea 100644 --- a/tavern/env.go +++ b/tavern/env.go @@ -6,6 +6,21 @@ import ( "strconv" ) +// EnvString represents a string that is configured using environment variables. +type EnvRequiredString struct { + Key string +} + +// String parsed from the environment variable. +func (env EnvRequiredString) String() string { + if val := os.Getenv(env.Key); val != "" { + return val + } else { + log.Printf("[ERROR] No value for required variable '%s' provided, Aborting.", env.Key) + panic("Missing variable") + } +} + // EnvString represents a string that is configured using environment variables. type EnvString struct { Key string From 7150c60d66bd8c90bb622ae3a247ef7a4747a640 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 17:54:30 +0000 Subject: [PATCH 022/141] static defaults are dangerous. --- docs/_docs/admin-guide/tavern.md | 11 +++++++++-- implants/lib/pb/src/xchacha.rs | 16 +++++++++++----- tavern/config.go | 14 +++++++++++++- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/docs/_docs/admin-guide/tavern.md b/docs/_docs/admin-guide/tavern.md index af715cfaa..cecf381f7 100644 --- a/docs/_docs/admin-guide/tavern.md +++ b/docs/_docs/admin-guide/tavern.md @@ -106,9 +106,16 @@ Below are some deployment gotchas and notes that we try to address with Terrafor ### Application layer crypto -Tavern recieves the encryption key for app layer crypto through an environment variable `IMIX_ENCRYPT_KEY`. This variable must be the same for agent builds and all running instances of Tavern. If the variable is not set Tavern will pick a random 64 character password. To retrieve the randomly set variable check the app logs +Tavern implements static key symmetric encryption using xchacha20-poly1305. -`2024/06/18 02:35:53 [WARN] No value for 'IMIX_ENCRYPT_KEY' provided, defaulting to /1oIbH~L#urAr0s75A:+0WMF8V*2I-0Z4Q6d[j-SBDBk]s4FCS&x~NmsVYOO0G6x` +Tavern recieves the encryption key for app layer crypto through an environment variable `IMIX_ENCRYPT_KEY`. This variable must be the same for agent builds and all running instances of Tavern. + +If the variable is not set Tavern and Imix will default to `I Don't care how small the room is I cast fireball`. This is a dangerous stop gap we've implemented while we build out the app layer crypto. Long term we're moving to asymmetric encryption and don't want to build a safe way to handle the shared key since it will be going away. For now implementers should not rely on the static key encryption or should take care to safely modify the key. + +The vaule is set in: + +* `realm/tavern/config.go`:`EnvImixEncryptKeyDefault` +* `realm/implants/lib/pb/src/xchacha.rs`:`IMIX_ENCRYPT_KEY_DEFAULT` ### Metrics diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index 21e5fe0f1..58b7e2bf4 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -17,15 +17,21 @@ pub struct ChaChaSvc { key: Vec, } -const IMIX_ENCRYPT_KEY: &str = env!( - "IMIX_ENCRYPT_KEY", - "Please set `IMIX_ENCRYPT_KEY` env variable" -); +// !!!! DANGER !!!!! +// This is the default static key set to ensure compatability between server and client +// in debug builds. This key must be changed in order to protect data. We're still in the +// process of implementing app layer crypto and this is temporary. Do not rely on the +// app layer crypto and ensure you're using proper TLS. +const IMIX_ENCRYPT_KEY_DEFAULT: &str = "I Don't care how small the room is I cast fireball"; +const IMIX_ENCRYPT_KEY: Option<&'static str> = option_env!("IMIX_ENCRYPT_KEY",); impl Default for ChaChaSvc { fn default() -> Self { Self { - key: IMIX_ENCRYPT_KEY.into(), + key: match IMIX_ENCRYPT_KEY { + Some(res) => res.into(), + None => IMIX_ENCRYPT_KEY_DEFAULT.into(), + }, } } } diff --git a/tavern/config.go b/tavern/config.go index acababfac..e0d6b3f05 100644 --- a/tavern/config.go +++ b/tavern/config.go @@ -20,6 +20,15 @@ import ( "realm.pub/tavern/tomes" ) +const REDACTED = "[REDACTED]" + +// !!!! DANGER !!!!! +// This is the default static key set to ensure compatability between server and client +// in debug builds. This key must be changed in order to protect data. We're still in the +// process of implementing app layer crypto and this is temporary. Do not rely on the +// app layer crypto and ensure you're using proper TLS. +const EnvImixEncryptKeyDefault = "I Don't care how small the room is I cast fireball" + var ( // EnvEnableTestData if set will populate the database with test data. // EnvEnableTestRunAndExit will start the application, but exit immediately after. @@ -73,7 +82,7 @@ var ( EnvEnableMetrics = EnvString{"ENABLE_METRICS", ""} // EnvImixEncryptKey is the secret key used to encrypt app layer communication - EnvImixEncryptKey = EnvRequiredString{"IMIX_ENCRYPT_KEY"} + EnvImixEncryptKey = EnvString{"IMIX_ENCRYPT_KEY", REDACTED} ) // Config holds information that controls the behaviour of Tavern @@ -198,6 +207,9 @@ func (cfg *Config) IsTestRunAndExitEnabled() bool { } func (cfg *Config) GetEncryptKey() []byte { + if EnvImixEncryptKey.String() == REDACTED { + return []byte(EnvImixEncryptKeyDefault) + } return []byte(EnvImixEncryptKey.String()) } From b5f908af6ff3b48d3dbb0c3d9555001afc8aa4fa Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 17:56:29 +0000 Subject: [PATCH 023/141] Remove set key from cicd --- .github/workflows/tests.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f1f5e56ac..1eb7d7208 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -77,8 +77,6 @@ jobs: with: tool: nextest,cargo-llvm-cov - name: 🔎 Run tests - env: - IMIX_ENCRYPT_KEY: "cicd" run: | cd ./implants/ && cargo fmt --check && From dc5afef9c6ea500be1025f443ca581fd853ca10b Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 17:59:03 +0000 Subject: [PATCH 024/141] Add var for encrypt key. --- terraform/main.tf | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/terraform/main.tf b/terraform/main.tf index 0ee9cfa21..8834db64e 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -88,6 +88,13 @@ variable "enable_metrics" { description = "Enable prometheus sidecar and Tavern metrics collection" default = false } +variable "imix_encrypt_key" { + type = string + description = "The encryption key tavern and imix should use to talk to each other" + sensitive = true + default = "" +} + provider "google" { project = var.gcp_project @@ -199,6 +206,10 @@ resource "google_cloud_run_service" "tavern" { name = "ENABLE_METRICS" value = var.enable_metrics ? "1" : "" } + env { + name = "IMIX_ENCRYPT_KEY" + value = var.imix_encrypt_key + } } // Only create prometheus sidecar if metrics enabled From fb78e542337a371d7db65fcc85dbc90f4881a656 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:02:21 +0000 Subject: [PATCH 025/141] Update terraform --- docs/_docs/admin-guide/tavern.md | 5 +++++ terraform/main.tf | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/_docs/admin-guide/tavern.md b/docs/_docs/admin-guide/tavern.md index cecf381f7..ff30a899a 100644 --- a/docs/_docs/admin-guide/tavern.md +++ b/docs/_docs/admin-guide/tavern.md @@ -116,6 +116,11 @@ The vaule is set in: * `realm/tavern/config.go`:`EnvImixEncryptKeyDefault` * `realm/implants/lib/pb/src/xchacha.rs`:`IMIX_ENCRYPT_KEY_DEFAULT` +* `realm/terraform/main.tf`:`imix_encrypt_key` + +| Env Var | Description | Default | Required | +| ------- | ----------- | ------- | -------- | +| IMIX_ENCRYPT_KEY | Define the encryption key for app layer crypto | "I Don't care how small the room is I cast fireball" | Yes | ### Metrics diff --git a/terraform/main.tf b/terraform/main.tf index 8834db64e..b9e813ee2 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -92,7 +92,7 @@ variable "imix_encrypt_key" { type = string description = "The encryption key tavern and imix should use to talk to each other" sensitive = true - default = "" + default = "I Don't care how small the room is I cast fireball" } From 1ac96c5f2f0e19f4e801a7436e799bf14a74c197 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:06:49 +0000 Subject: [PATCH 026/141] Fix debug and errors. --- tavern/internal/cryptocodec/cryptocodec.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tavern/internal/cryptocodec/cryptocodec.go b/tavern/internal/cryptocodec/cryptocodec.go index 801d78854..e65a9094a 100644 --- a/tavern/internal/cryptocodec/cryptocodec.go +++ b/tavern/internal/cryptocodec/cryptocodec.go @@ -28,18 +28,14 @@ func NewStreamDecryptCodec() StreamDecryptCodec { } func (s StreamDecryptCodec) Marshal(v any) ([]byte, error) { - log.Println("Marshal") proto := encoding.GetCodec("proto") res, err := proto.Marshal(v) - log.Println("Marshal buf ", res) enc_res := s.Csvc.Encrypt(res) return enc_res, err } func (s StreamDecryptCodec) Unmarshal(buf []byte, v any) error { - log.Println("Decrypt:", buf) dec_buf := s.Csvc.Decrypt(buf) - log.Println("Unmarshal:", dec_buf) proto := encoding.GetCodec("proto") return proto.Unmarshal(dec_buf, v) } @@ -94,7 +90,8 @@ func (csvc *CryptoSvc) Decrypt(in_arr []byte) []byte { func (csvc *CryptoSvc) Encrypt(in_arr []byte) []byte { nonce := make([]byte, csvc.Aead.NonceSize(), csvc.Aead.NonceSize()+len(in_arr)+csvc.Aead.Overhead()) if _, err := rand.Read(nonce); err != nil { - panic(err) + fmt.Printf("Failed to encrypt %v\n", err) + return []byte{} } encryptedMsg := csvc.Aead.Seal(nonce, nonce, in_arr, nil) return encryptedMsg From 7c637ae4d408bc600e32b6d03050a831f447c321 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:08:48 +0000 Subject: [PATCH 027/141] Updating warnings. --- implants/lib/pb/src/xchacha.rs | 2 +- tavern/config.go | 2 +- terraform/main.tf | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index 58b7e2bf4..7eb51d889 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -21,7 +21,7 @@ pub struct ChaChaSvc { // This is the default static key set to ensure compatability between server and client // in debug builds. This key must be changed in order to protect data. We're still in the // process of implementing app layer crypto and this is temporary. Do not rely on the -// app layer crypto and ensure you're using proper TLS. +// app layer crypto without changing this default. const IMIX_ENCRYPT_KEY_DEFAULT: &str = "I Don't care how small the room is I cast fireball"; const IMIX_ENCRYPT_KEY: Option<&'static str> = option_env!("IMIX_ENCRYPT_KEY",); diff --git a/tavern/config.go b/tavern/config.go index e0d6b3f05..80df283dd 100644 --- a/tavern/config.go +++ b/tavern/config.go @@ -26,7 +26,7 @@ const REDACTED = "[REDACTED]" // This is the default static key set to ensure compatability between server and client // in debug builds. This key must be changed in order to protect data. We're still in the // process of implementing app layer crypto and this is temporary. Do not rely on the -// app layer crypto and ensure you're using proper TLS. +// app layer crypto without changing this default. const EnvImixEncryptKeyDefault = "I Don't care how small the room is I cast fireball" var ( diff --git a/terraform/main.tf b/terraform/main.tf index b9e813ee2..c740acfa1 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -88,6 +88,11 @@ variable "enable_metrics" { description = "Enable prometheus sidecar and Tavern metrics collection" default = false } +// !!!! DANGER !!!!! +// This is the default static key set to ensure compatability between server and client +// in debug builds. This key must be changed in order to protect data. We're still in the +// process of implementing app layer crypto and this is temporary. Do not rely on the +// app layer crypto without changing this default. variable "imix_encrypt_key" { type = string description = "The encryption key tavern and imix should use to talk to each other" From 5cb02e9df3fcf7378ccfd27f758a4d336175ef55 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:10:17 +0000 Subject: [PATCH 028/141] Fix prints --- implants/lib/pb/src/xchacha.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index 7eb51d889..6ba50daf4 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -82,7 +82,8 @@ where fn encode(&mut self, item: Self::Item, buf: &mut EncodeBuf<'_>) -> Result<(), Self::Error> { if !buf.has_remaining_mut() { // Can't add to the buffer. - println!("DANGER can't add to the buffer."); + #[cfg(debug_assertions)] + log::debug!("DANGER can't add to the buffer."); } let key = self.1.key.as_slice(); @@ -95,13 +96,11 @@ where let pt_vec = item.encode_to_vec(); - println!("ENCODE DEC: {:?}", pt_vec); - // let _ = buf.writer().write_all(&pt_vec); - let ciphertext = match cipher.encrypt(&nonce, pt_vec.as_slice()) { Ok(ct) => ct, Err(err) => { - println!("err: {:?}", err); + #[cfg(debug_assertions)] + log::debug!("err: {:?}", err); return Err(Status::new(tonic::Code::Internal, err.to_string())); } }; @@ -109,8 +108,6 @@ where let _ = buf.writer().write_all(nonce.as_slice()); buf.writer().write_all(ciphertext.as_slice())?; - println!("ENCODE ENC: {:?}", buf); - Ok(()) } } @@ -136,7 +133,8 @@ where let bytes_read = match reader.read(&mut bytes_in) { Ok(n) => n, Err(err) => { - println!("err: {:?}", err); + #[cfg(debug_assertions)] + log::debug!("err: {:?}", err); return Err(Status::new(tonic::Code::Internal, err.to_string())); } }; @@ -154,7 +152,8 @@ where let plaintext = match cipher.decrypt(GenericArray::from_slice(nonce), ciphertext.as_ref()) { Ok(pt) => pt, Err(err) => { - println!("err: {:?}", err); + #[cfg(debug_assertions)] + log::debug!("err: {:?}", err); return Err(Status::new(tonic::Code::Internal, err.to_string())); } }; From cdaaf393627ddac65885939e411b1c82f154d1e0 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:12:25 +0000 Subject: [PATCH 029/141] Remove required string. --- tavern/env.go | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/tavern/env.go b/tavern/env.go index 7e9e3d9ea..80471e72e 100644 --- a/tavern/env.go +++ b/tavern/env.go @@ -6,21 +6,6 @@ import ( "strconv" ) -// EnvString represents a string that is configured using environment variables. -type EnvRequiredString struct { - Key string -} - -// String parsed from the environment variable. -func (env EnvRequiredString) String() string { - if val := os.Getenv(env.Key); val != "" { - return val - } else { - log.Printf("[ERROR] No value for required variable '%s' provided, Aborting.", env.Key) - panic("Missing variable") - } -} - // EnvString represents a string that is configured using environment variables. type EnvString struct { Key string From 6397e697c8d44d6a9ed31fdd93804b196d81ec28 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:13:56 +0000 Subject: [PATCH 030/141] Revert example tome --- tavern/tomes/example/main.eldritch | 11 +---------- tavern/tomes/example/metadata.yml | 5 +++++ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/tavern/tomes/example/main.eldritch b/tavern/tomes/example/main.eldritch index aee9d8c0b..693ffb9ac 100644 --- a/tavern/tomes/example/main.eldritch +++ b/tavern/tomes/example/main.eldritch @@ -1,10 +1 @@ -assets.copy("example/linux/test-file", "/tmp/winnnnz") -print(file.read("/tmp/winnnnz")) -test_hash = crypto.hash_file("/tmp/winnnnz", "SHA256") -if not "30c2bf79fb57fe7c9bea00a2bfe0cb2e9b3ce0b694aa63c633a2bd44a5c87e56" == test_hash: - print("Hashes don't match!") - print(file.read("/tmp/winnnnz")) - -report.file("/etc/passwd") -print("Success! ✅") -file.remove("/tmp/winnnnz") +print(input_params['msg']) diff --git a/tavern/tomes/example/metadata.yml b/tavern/tomes/example/metadata.yml index 5b6704a33..ea86b7123 100644 --- a/tavern/tomes/example/metadata.yml +++ b/tavern/tomes/example/metadata.yml @@ -3,3 +3,8 @@ description: An example tome! author: kcarretto support_model: FIRST_PARTY tactic: UNSPECIFIED +paramdefs: +- label: Message + name: msg + placeholder: Something to print + type: string From 7833462149515684f62cbb6f7895a2ceb1796f65 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:45:06 +0000 Subject: [PATCH 031/141] Remove todo --- tavern/internal/cryptocodec/cryptocodec.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/tavern/internal/cryptocodec/cryptocodec.go b/tavern/internal/cryptocodec/cryptocodec.go index e65a9094a..05ffb4b3d 100644 --- a/tavern/internal/cryptocodec/cryptocodec.go +++ b/tavern/internal/cryptocodec/cryptocodec.go @@ -17,8 +17,6 @@ func init() { encoding.RegisterCodec(StreamDecryptCodec{}) } -// TODO decyrpt and encrypt in place - type StreamDecryptCodec struct { Csvc CryptoSvc } From fbf83b1f0456e8cfdf9339f35ebb7f0f66cfb8ed Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:49:07 +0000 Subject: [PATCH 032/141] Remove deny_warnings --- implants/golem/src/lib.rs | 2 -- implants/golem/src/main.rs | 2 -- implants/imix/src/lib.rs | 2 -- implants/imix/src/main.rs | 1 - implants/lib/eldritch/src/lib.rs | 2 -- 5 files changed, 9 deletions(-) diff --git a/implants/golem/src/lib.rs b/implants/golem/src/lib.rs index 7ed0a3a55..537b47def 100644 --- a/implants/golem/src/lib.rs +++ b/implants/golem/src/lib.rs @@ -1,5 +1,3 @@ -#![deny(warnings)] - #[derive(Debug)] pub enum Error { Io(std::io::Error), diff --git a/implants/golem/src/main.rs b/implants/golem/src/main.rs index 8f6be18e1..df4c45c09 100644 --- a/implants/golem/src/main.rs +++ b/implants/golem/src/main.rs @@ -1,5 +1,3 @@ -#![deny(warnings)] - extern crate eldritch; extern crate golem; diff --git a/implants/imix/src/lib.rs b/implants/imix/src/lib.rs index 9de3c4e10..8b62e1fdb 100644 --- a/implants/imix/src/lib.rs +++ b/implants/imix/src/lib.rs @@ -1,5 +1,3 @@ -#![deny(warnings)] - pub mod agent; mod config; mod install; diff --git a/implants/imix/src/main.rs b/implants/imix/src/main.rs index 501e3c2a4..a15974510 100644 --- a/implants/imix/src/main.rs +++ b/implants/imix/src/main.rs @@ -1,5 +1,4 @@ #![windows_subsystem = "windows"] -#![deny(warnings)] #[cfg(all(feature = "win_service", windows))] #[macro_use] diff --git a/implants/lib/eldritch/src/lib.rs b/implants/lib/eldritch/src/lib.rs index e6a1c046b..b602966ae 100644 --- a/implants/lib/eldritch/src/lib.rs +++ b/implants/lib/eldritch/src/lib.rs @@ -1,5 +1,3 @@ -#![deny(warnings)] - pub mod assets; pub mod crypto; pub mod file; From 6cf358b04fb7f6c18596ce622b28298243fd56b9 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 21:38:03 +0000 Subject: [PATCH 033/141] Remove docs - not supported. --- docs/_docs/admin-guide/tavern.md | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/docs/_docs/admin-guide/tavern.md b/docs/_docs/admin-guide/tavern.md index ff30a899a..16279f494 100644 --- a/docs/_docs/admin-guide/tavern.md +++ b/docs/_docs/admin-guide/tavern.md @@ -104,24 +104,6 @@ Below are some deployment gotchas and notes that we try to address with Terrafor ## Configuration -### Application layer crypto - -Tavern implements static key symmetric encryption using xchacha20-poly1305. - -Tavern recieves the encryption key for app layer crypto through an environment variable `IMIX_ENCRYPT_KEY`. This variable must be the same for agent builds and all running instances of Tavern. - -If the variable is not set Tavern and Imix will default to `I Don't care how small the room is I cast fireball`. This is a dangerous stop gap we've implemented while we build out the app layer crypto. Long term we're moving to asymmetric encryption and don't want to build a safe way to handle the shared key since it will be going away. For now implementers should not rely on the static key encryption or should take care to safely modify the key. - -The vaule is set in: - -* `realm/tavern/config.go`:`EnvImixEncryptKeyDefault` -* `realm/implants/lib/pb/src/xchacha.rs`:`IMIX_ENCRYPT_KEY_DEFAULT` -* `realm/terraform/main.tf`:`imix_encrypt_key` - -| Env Var | Description | Default | Required | -| ------- | ----------- | ------- | -------- | -| IMIX_ENCRYPT_KEY | Define the encryption key for app layer crypto | "I Don't care how small the room is I cast fireball" | Yes | - ### Metrics By default, Tavern does not export metrics. You may use the below environment configuration variables to enable [Prometheus](https://prometheus.io/docs/introduction/overview/) metric collection. These metrics become available at the "/metrics" endpoint configured. These metrics are hosted on a separate HTTP server such that it can be restricted to localhost (default). This is because the endpoint is unauthenticated, and would leak sensitive information if it was accessible. From 75273d8de9edc5dd4d492a2571696335ad171342 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 21:51:21 +0000 Subject: [PATCH 034/141] No docs --- docs/_docs/user-guide/imix.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docs/_docs/user-guide/imix.md b/docs/_docs/user-guide/imix.md index c8ff8a1d8..fa07c5a61 100644 --- a/docs/_docs/user-guide/imix.md +++ b/docs/_docs/user-guide/imix.md @@ -15,7 +15,6 @@ Imix has compile-time configuration, that may be specified using environment var | Env Var | Description | Default | Required | | ------- | ----------- | ------- | -------- | -| IMIX_ENCRYPT_KEY | Secret key to encrypt app layer crypto | - | Yes | | IMIX_CALLBACK_URI | URI for initial callbacks (must specify a scheme, e.g. `http://`) | `http://127.0.0.1:80` | No | | IMIX_CALLBACK_INTERVAL | Duration between callbacks, in seconds. | `5` | No | | IMIX_RETRY_INTERVAL | Duration to wait before restarting the agent loop if an error occurs, in seconds. | `5` | No | @@ -69,8 +68,6 @@ sudo apt update sudo apt install musl-tools cd realm/implants/imix/ -IMIX_ENCRYPT_KEY=$(LC_ALL=C tr -dc '[:graph:]' Date: Wed, 19 Jun 2024 22:00:11 +0000 Subject: [PATCH 035/141] Revert "Remove deny_warnings" This reverts commit fbf83b1f0456e8cfdf9339f35ebb7f0f66cfb8ed. --- implants/golem/src/lib.rs | 2 ++ implants/golem/src/main.rs | 2 ++ implants/imix/src/lib.rs | 2 ++ implants/imix/src/main.rs | 1 + implants/lib/eldritch/src/lib.rs | 2 ++ 5 files changed, 9 insertions(+) diff --git a/implants/golem/src/lib.rs b/implants/golem/src/lib.rs index 537b47def..7ed0a3a55 100644 --- a/implants/golem/src/lib.rs +++ b/implants/golem/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(warnings)] + #[derive(Debug)] pub enum Error { Io(std::io::Error), diff --git a/implants/golem/src/main.rs b/implants/golem/src/main.rs index df4c45c09..8f6be18e1 100644 --- a/implants/golem/src/main.rs +++ b/implants/golem/src/main.rs @@ -1,3 +1,5 @@ +#![deny(warnings)] + extern crate eldritch; extern crate golem; diff --git a/implants/imix/src/lib.rs b/implants/imix/src/lib.rs index 8b62e1fdb..9de3c4e10 100644 --- a/implants/imix/src/lib.rs +++ b/implants/imix/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(warnings)] + pub mod agent; mod config; mod install; diff --git a/implants/imix/src/main.rs b/implants/imix/src/main.rs index a15974510..501e3c2a4 100644 --- a/implants/imix/src/main.rs +++ b/implants/imix/src/main.rs @@ -1,4 +1,5 @@ #![windows_subsystem = "windows"] +#![deny(warnings)] #[cfg(all(feature = "win_service", windows))] #[macro_use] diff --git a/implants/lib/eldritch/src/lib.rs b/implants/lib/eldritch/src/lib.rs index b602966ae..e6a1c046b 100644 --- a/implants/lib/eldritch/src/lib.rs +++ b/implants/lib/eldritch/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(warnings)] + pub mod assets; pub mod crypto; pub mod file; From d9bf87dae7cb60d3d5122376416ab51a05117f30 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Sat, 29 Jun 2024 18:34:18 -0500 Subject: [PATCH 036/141] App layer crypto codec asym (#784) * Rough POC * Update key * Debug * Works on my computer. * Claenup * Unused edps --- implants/Cargo.toml | 2 + implants/lib/pb/Cargo.toml | 6 +- implants/lib/pb/src/xchacha.rs | 124 +++++++++++----- tavern/app.go | 29 +++- tavern/internal/cryptocodec/cryptocodec.go | 163 +++++++++++++++++---- 5 files changed, 254 insertions(+), 70 deletions(-) diff --git a/implants/Cargo.toml b/implants/Cargo.toml index 175db6a1a..1e0a5234c 100644 --- a/implants/Cargo.toml +++ b/implants/Cargo.toml @@ -16,6 +16,7 @@ async-recursion = "1.0.0" async-trait = "0.1.68" base64 = "0.21.4" chrono = "0.4.34" +const-decoder = "0.3.0" clap = "3.2.23" default-net = "0.13.1" derive_more = "=0.99.17" @@ -83,6 +84,7 @@ windows-sys = "0.45.0" winreg = "0.51.0" chacha20poly1305 = "0.10.1" bytes = "1.6.0" +x25519-dalek = "2.0.1" [profile.release] diff --git a/implants/lib/pb/Cargo.toml b/implants/lib/pb/Cargo.toml index 00f0264d7..3ceae01b3 100644 --- a/implants/lib/pb/Cargo.toml +++ b/implants/lib/pb/Cargo.toml @@ -4,16 +4,20 @@ version = "0.0.5" edition = "2021" [dependencies] +anyhow = { workspace = true } log = { workspace = true } prost = { workspace = true } prost-types = { workspace = true } +rand_chacha = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } tokio-stream = { workspace = true } tonic = { workspace = true, features = ["tls-roots"] } +const-decoder = { workspace = true } chacha20poly1305 = { workspace = true } bytes = { workspace = true } -sha2 = { workspace = true } rand = { workspace = true } +x25519-dalek = { workspace = true } + [build-dependencies] tonic-build = { workspace = true, features = ["prost"] } diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index 6ba50daf4..d470fbebf 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -1,38 +1,53 @@ +use anyhow::{Context, Result}; use bytes::{Buf, BufMut}; use chacha20poly1305::{aead::generic_array::GenericArray, aead::Aead, AeadCore, KeyInit}; +use const_decoder::Decoder as const_decode; use prost::Message; use rand::rngs::OsRng; -use sha2::{Digest, Sha256}; +use rand_chacha::rand_core::SeedableRng; use std::{ + collections::HashMap, io::{Read, Write}, marker::PhantomData, + sync::{Mutex, OnceLock}, }; use tonic::{ codec::{Codec, DecodeBuf, Decoder, EncodeBuf, Encoder}, Status, }; +use x25519_dalek::{EphemeralSecret, PublicKey}; -#[derive(Debug, Clone)] -pub struct ChaChaSvc { - key: Vec, +const SERVER_PUBKEY_STR: &str = env!("SERVER_PUBKEY"); +const SERVER_PUBKEY: [u8; 32] = const_decode::Base64.decode(SERVER_PUBKEY_STR.as_bytes()); + +// ------------ + +fn key_history() -> &'static Mutex> { + static ARRAY: OnceLock>> = OnceLock::new(); + ARRAY.get_or_init(|| Mutex::new(HashMap::new())) +} + +fn add_key_history(pub_key: [u8; 32], shared_secret: [u8; 32]) { + key_history().lock().unwrap().insert(pub_key, shared_secret); // Mutex's must unwrap } -// !!!! DANGER !!!!! -// This is the default static key set to ensure compatability between server and client -// in debug builds. This key must be changed in order to protect data. We're still in the -// process of implementing app layer crypto and this is temporary. Do not rely on the -// app layer crypto without changing this default. -const IMIX_ENCRYPT_KEY_DEFAULT: &str = "I Don't care how small the room is I cast fireball"; -const IMIX_ENCRYPT_KEY: Option<&'static str> = option_env!("IMIX_ENCRYPT_KEY",); +fn get_key(pub_key: [u8; 32]) -> Result<[u8; 32]> { + let res = *key_history() + .lock() + .unwrap() // Mutex's must unwrap + .get(&pub_key) + .context("Key not found")?; + Ok(res) +} + +// ------------ + +#[derive(Debug, Clone)] +pub struct ChaChaSvc {} impl Default for ChaChaSvc { fn default() -> Self { - Self { - key: match IMIX_ENCRYPT_KEY { - Some(res) => res.into(), - None => IMIX_ENCRYPT_KEY_DEFAULT.into(), - }, - } + Self {} } } @@ -86,16 +101,26 @@ where log::debug!("DANGER can't add to the buffer."); } - let key = self.1.key.as_slice(); - let mut hasher = Sha256::new(); - hasher.update(key); - let key_hash = hasher.finalize(); + // Store server pubkey + let server_public = PublicKey::from(SERVER_PUBKEY); - let cipher = chacha20poly1305::XChaCha20Poly1305::new(GenericArray::from_slice(&key_hash)); + // Generate ephemeral keys + let rng = rand_chacha::ChaCha20Rng::from_entropy(); + let client_secret = EphemeralSecret::random_from_rng(rng); + let client_public = PublicKey::from(&client_secret); + + // Generate shared secret + let shared_secret = client_secret.diffie_hellman(&server_public); + add_key_history(*client_public.as_bytes(), *shared_secret.as_bytes()); + + // Generate nonce + let cipher = chacha20poly1305::XChaCha20Poly1305::new(GenericArray::from_slice( + shared_secret.as_bytes(), + )); let nonce = chacha20poly1305::XChaCha20Poly1305::generate_nonce(&mut OsRng); + // Encrypt data let pt_vec = item.encode_to_vec(); - let ciphertext = match cipher.encrypt(&nonce, pt_vec.as_slice()) { Ok(ct) => ct, Err(err) => { @@ -105,7 +130,9 @@ where } }; - let _ = buf.writer().write_all(nonce.as_slice()); + // Write pubkey + nonce + cipher text + buf.writer().write_all(client_public.as_bytes()); + buf.writer().write_all(nonce.as_slice()); buf.writer().write_all(ciphertext.as_slice())?; Ok(()) @@ -128,6 +155,7 @@ where type Error = Status; fn decode(&mut self, buf: &mut DecodeBuf<'_>) -> Result, Self::Error> { + // public key + xchacha nonce + ciphertext let mut reader = buf.reader(); let mut bytes_in = vec![0; DEFAULT_CODEC_BUFFER_SIZE]; let bytes_read = match reader.read(&mut bytes_in) { @@ -139,25 +167,47 @@ where } }; - let ciphertext = &bytes_in[0..bytes_read]; - let nonce = &ciphertext[0..24]; - let ciphertext = &ciphertext[24..]; - - let key = self.1.key.as_slice(); - let mut hasher = Sha256::new(); - hasher.update(key); - let key_hash = hasher.finalize(); - let cipher = chacha20poly1305::XChaCha20Poly1305::new(GenericArray::from_slice(&key_hash)); - + // TODO validate buffer size to avoid index out of bounds accesses + let buf = bytes_in + .get(0..bytes_read) + .context("Bytes read doesn't match buffer size") + .map_err(from_anyhow_error)?; + + let client_public = buf + .get(0..32) + .context("Input buffer doesn't have enough bytes for public key") + .map_err(from_anyhow_error)?; + + let nonce = buf + .get(32..56) + .context("Input buffer doesn't have enough bytes for nonce") + .map_err(from_anyhow_error)?; + + let ciphertext = buf + .get(56..) + .context("Input buffer doesn't have enough bytes for ciphertext") + .map_err(from_anyhow_error)?; + + // Get private key based on messages public key + let tmp_client_public_bytes = client_public.to_vec(); + let client_public_bytes = tmp_client_public_bytes.try_into().unwrap(); // Bruh idk how to not unwrap this :sob: + + let client_private_bytes = get_key(client_public_bytes).map_err(from_anyhow_error)?; + let cipher = chacha20poly1305::XChaCha20Poly1305::new(GenericArray::from_slice( + &client_private_bytes, + )); + + // Decrypt message let plaintext = match cipher.decrypt(GenericArray::from_slice(nonce), ciphertext.as_ref()) { Ok(pt) => pt, Err(err) => { #[cfg(debug_assertions)] - log::debug!("err: {:?}", err); + log::debug!("Error decrypting response: {:?}", err); return Err(Status::new(tonic::Code::Internal, err.to_string())); } }; + // Serialize let item = Message::decode(bytes::Bytes::from(plaintext)) .map(Option::Some) .map_err(from_decode_error)?; @@ -166,6 +216,10 @@ where } } +fn from_anyhow_error(error: anyhow::Error) -> Status { + Status::new(tonic::Code::Internal, error.to_string()) +} + fn from_decode_error(error: prost::DecodeError) -> Status { // Map Protobuf parse errors to an INTERNAL status code, as per // https://github.com/grpc/grpc/blob/master/doc/statuscodes.md diff --git a/tavern/app.go b/tavern/app.go index 78f712e0e..ea141b04f 100644 --- a/tavern/app.go +++ b/tavern/app.go @@ -2,8 +2,10 @@ package main import ( "context" + "crypto/ecdh" "crypto/ed25519" "crypto/rand" + "encoding/base64" "encoding/json" "fmt" "log" @@ -195,7 +197,7 @@ func NewServer(ctx context.Context, options ...func(*Config)) (*Server, error) { AllowUnactivated: true, }, "/c2.C2/": tavernhttp.Endpoint{ - Handler: newGRPCHandler(client, grpcShellMux, cfg.GetEncryptKey()), + Handler: newGRPCHandler(client, grpcShellMux), AllowUnauthenticated: true, AllowUnactivated: true, }, @@ -284,7 +286,7 @@ func newGraphQLHandler(client *ent.Client, repoImporter graphql.RepoImporter) ht oc := gqlgraphql.GetOperationContext(ctx) reqVars, err := json.Marshal(oc.Variables) if err != nil { - gqlLogger.Printf("[ERROR] failed to marshal variables to JSON: %v", err) + gqlLogger.Printf("[ERROR] failed to marshal variables to JSON: %v\n", err) return next(ctx) } @@ -305,10 +307,29 @@ func newGraphQLHandler(client *ent.Client, repoImporter graphql.RepoImporter) ht }) } -func newGRPCHandler(client *ent.Client, grpcShellMux *stream.Mux, crypto_key []byte) http.Handler { +func generate_key_pair() (*ecdh.PublicKey, *ecdh.PrivateKey) { + x22519 := ecdh.X25519() + priv_key, err := x22519.GenerateKey(rand.Reader) + if err != nil { + log.Printf("[ERROR] Failed to generate private key: %v\n", err) + panic("[ERROR] Failed to generate private key") + } + public_key, err := x22519.NewPublicKey(priv_key.PublicKey().Bytes()) + if err != nil { + log.Printf("[ERROR] Failed to generate public key: %v\n", err) + panic("[ERROR] Failed to generate public key") + } + + return public_key, priv_key +} + +func newGRPCHandler(client *ent.Client, grpcShellMux *stream.Mux) http.Handler { + public_key, priv_key := generate_key_pair() + log.Println("[INFO] Public key: ", base64.StdEncoding.EncodeToString(public_key.Bytes())) + log.Println("[INFO] Private key: ", base64.StdEncoding.EncodeToString(priv_key.Bytes())) c2srv := c2.New(client, grpcShellMux) xchacha := cryptocodec.StreamDecryptCodec{ - Csvc: cryptocodec.NewCryptoSvc(crypto_key), + Csvc: cryptocodec.NewCryptoSvc(priv_key), } grpcSrv := grpc.NewServer( grpc.ForceServerCodec(xchacha), diff --git a/tavern/internal/cryptocodec/cryptocodec.go b/tavern/internal/cryptocodec/cryptocodec.go index 05ffb4b3d..d09fb21db 100644 --- a/tavern/internal/cryptocodec/cryptocodec.go +++ b/tavern/internal/cryptocodec/cryptocodec.go @@ -1,19 +1,29 @@ package cryptocodec import ( - "crypto/cipher" + "bytes" + "crypto/ecdh" "crypto/rand" - "crypto/sha256" + "errors" "fmt" "log" + "runtime" + "strconv" + "sync" + "github.com/cloudflare/circl/dh/x25519" "golang.org/x/crypto/chacha20poly1305" "google.golang.org/grpc/encoding" ) +// TODO: Switch to a gomap and mutex. +var session_pub_keys = sync.Map{} + +// TODO: Should we make this a random long byte array in case it gets used anywhere to avoid encrypting data with a week key? - Sliver handles errors in this way. +var FAILURE_BYTES = []byte{} + func init() { - log.Println("Loading xchacha20-poly1305") - // Probably want to use the `ForceServerCodec` option instead. + log.Println("[INFO] Loading xchacha20-poly1305") encoding.RegisterCodec(StreamDecryptCodec{}) } @@ -26,6 +36,11 @@ func NewStreamDecryptCodec() StreamDecryptCodec { } func (s StreamDecryptCodec) Marshal(v any) ([]byte, error) { + id, err := goid() + if err != nil { + log.Println("[ERROR] Unable to find GOID ", id) + return FAILURE_BYTES, err + } proto := encoding.GetCodec("proto") res, err := proto.Marshal(v) enc_res := s.Csvc.Encrypt(res) @@ -33,7 +48,13 @@ func (s StreamDecryptCodec) Marshal(v any) ([]byte, error) { } func (s StreamDecryptCodec) Unmarshal(buf []byte, v any) error { - dec_buf := s.Csvc.Decrypt(buf) + id, err := goid() + if err != nil { + log.Println("[ERROR] Unable to find GOID ", id) + return err + } + dec_buf, pub_key := s.Csvc.Decrypt(buf) + s.Csvc.SetAgentPubkey(pub_key) proto := encoding.GetCodec("proto") return proto.Unmarshal(dec_buf, v) } @@ -43,54 +64,136 @@ func (s StreamDecryptCodec) Name() string { } type CryptoSvc struct { - Aead cipher.AEAD + // Aead cipher.AEAD + priv_key *ecdh.PrivateKey } -func NewCryptoSvc(key []byte) CryptoSvc { - hasher := sha256.New() - hasher.Write(key) - key = hasher.Sum(nil) - aead, err := chacha20poly1305.NewX(key) +func NewCryptoSvc(priv_key *ecdh.PrivateKey) CryptoSvc { + return CryptoSvc{ + priv_key: priv_key, + } +} +func (csvc *CryptoSvc) GetAgentPubkey() []byte { + id, err := goid() if err != nil { - panic(err) + log.Println("[ERROR] Unable to find GOID ", id) + return FAILURE_BYTES + } + res, ok := session_pub_keys.Load(id) + if !ok { + log.Println("[ERROR] Public key not found") } + return res.([]byte) +} - nonce := make([]byte, aead.NonceSize()) - if _, err := rand.Read(nonce); err != nil { - panic(err) +func (csvc *CryptoSvc) SetAgentPubkey(client_pub_key []byte) { + id, err := goid() + if err != nil { + log.Println("[ERROR] Failed to get goid") } + session_pub_keys.Store(id, client_pub_key) +} - res := CryptoSvc{ - Aead: aead, +func (csvc *CryptoSvc) generate_shared_key(client_pub_key_bytes []byte) []byte { + fmt.Println("[DEBUG] client_pub_key_bytes: ", client_pub_key_bytes) + x22519_curve := ecdh.X25519() + client_pub_key, err := x22519_curve.NewPublicKey(client_pub_key_bytes) + if err != nil { + log.Printf("[ERROR] Failed to create public key %v", err) + return FAILURE_BYTES } - return res + shared_key, err := csvc.priv_key.ECDH(client_pub_key) + if err != nil { + log.Printf("[ERROR] Failed to get shared secret %v", err) + return FAILURE_BYTES + } + return shared_key } -func (csvc *CryptoSvc) Decrypt(in_arr []byte) []byte { - if len(in_arr) < csvc.Aead.NonceSize() { - fmt.Printf("Input bytes to short %d expected %d\n", len(in_arr), csvc.Aead.NonceSize()) - return []byte{} +func (csvc *CryptoSvc) Decrypt(in_arr []byte) ([]byte, []byte) { + // Read in pub key + if len(in_arr) < x25519.Size { + fmt.Printf("Input bytes to short %d expected at least %d\n", len(in_arr), x25519.Size) + return FAILURE_BYTES, FAILURE_BYTES + } + + client_pub_key_bytes := in_arr[:x25519.Size] + csvc.SetAgentPubkey(client_pub_key_bytes) + + // Generate shared secret + derived_key := csvc.generate_shared_key(client_pub_key_bytes) + + log.Println("[DEBUG] derived_key: ", derived_key) + aead, err := chacha20poly1305.NewX(derived_key) + if err != nil { + log.Printf("[ERROR] Failed to create xchacha key %v", err) + return FAILURE_BYTES, FAILURE_BYTES } - nonce, ciphertext := in_arr[:csvc.Aead.NonceSize()], in_arr[csvc.Aead.NonceSize():] - plaintext, err := csvc.Aead.Open(nil, nonce, ciphertext, nil) + // Progress in_arr buf + in_arr = in_arr[x25519.Size:] + + // Read nonce + if len(in_arr) < aead.NonceSize() { + fmt.Printf("Input bytes to short %d expected at least %d\n", len(in_arr), aead.NonceSize()) + return FAILURE_BYTES, FAILURE_BYTES + } + nonce, ciphertext := in_arr[:aead.NonceSize()], in_arr[aead.NonceSize():] + + // Decrypt + plaintext, err := aead.Open(nil, nonce, ciphertext, nil) if err != nil { fmt.Printf("Failed to decrypt %v\n", err) - return []byte{} + return FAILURE_BYTES, FAILURE_BYTES } - return plaintext + return plaintext, client_pub_key_bytes } +// TODO: Don't use [] ref. func (csvc *CryptoSvc) Encrypt(in_arr []byte) []byte { - nonce := make([]byte, csvc.Aead.NonceSize(), csvc.Aead.NonceSize()+len(in_arr)+csvc.Aead.Overhead()) + // Get the client pub key? + client_pub_key_bytes := csvc.GetAgentPubkey() + fmt.Println("[DEBUG] Got pub key: ", client_pub_key_bytes) + + // Generate shared secret + shared_key := csvc.generate_shared_key(client_pub_key_bytes) + aead, err := chacha20poly1305.NewX(shared_key) + if err != nil { + log.Printf("[ERROR] Failed to create xchacha key %v", err) + return FAILURE_BYTES + } + + nonce := make([]byte, aead.NonceSize(), aead.NonceSize()+len(in_arr)+aead.Overhead()) if _, err := rand.Read(nonce); err != nil { fmt.Printf("Failed to encrypt %v\n", err) - return []byte{} + return FAILURE_BYTES + } + encryptedMsg := aead.Seal(nonce, nonce, in_arr, nil) + return append(client_pub_key_bytes, encryptedMsg...) +} + +// TODO: Find a better way +// This is terrible, slow, and should never be used. +func goid() (int, error) { + buf := make([]byte, 32) + n := runtime.Stack(buf, false) + buf = buf[:n] + // goroutine 1 [running]: ... + var goroutinePrefix = []byte("goroutine ") + var errBadStack = errors.New("invalid runtime.Stack output") + buf, ok := bytes.CutPrefix(buf, goroutinePrefix) + if !ok { + return 0, errBadStack + } + + i := bytes.IndexByte(buf, ' ') + if i < 0 { + return 0, errBadStack } - encryptedMsg := csvc.Aead.Seal(nonce, nonce, in_arr, nil) - return encryptedMsg + + return strconv.Atoi(string(buf[:i])) } From d1f0a849aa961385e51b07be84e333baf7aa4716 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 1 Jul 2024 00:50:01 +0000 Subject: [PATCH 037/141] Debug file secrets manager --- tavern/internal/secrets/debug_file.go | 178 +++++++++++++++++++++ tavern/internal/secrets/debug_file_test.go | 93 +++++++++++ tavern/internal/secrets/secrets.go | 7 + 3 files changed, 278 insertions(+) create mode 100644 tavern/internal/secrets/debug_file.go create mode 100644 tavern/internal/secrets/debug_file_test.go create mode 100644 tavern/internal/secrets/secrets.go diff --git a/tavern/internal/secrets/debug_file.go b/tavern/internal/secrets/debug_file.go new file mode 100644 index 000000000..04aee10fd --- /dev/null +++ b/tavern/internal/secrets/debug_file.go @@ -0,0 +1,178 @@ +package secrets + +import ( + "errors" + "fmt" + "log" + "os" + + "gopkg.in/yaml.v3" +) + +const DEFAULT_PERMS = 0644 +const DELIMITER = "=" +const MEGABYTES = 1000000 +const MAX_FILE_SIZE = 128 * MEGABYTES + +type Secret struct { + Key string + Value string +} + +type Secrets struct { + Secrets []Secret +} + +type DebugFileSecrets struct { + Name string + Path string +} + +func NewDebugFileSecrets(path string) SecretsManager { + return DebugFileSecrets{ + Name: "DebugFileSecrets", + Path: path, + } +} + +func (s DebugFileSecrets) GetName() string { + return s.Name +} + +func (s DebugFileSecrets) SetValue(key string, value string) (string, error) { + path, err := s.createSecretsFile() + if err != nil { + log.Printf("[ERROR] Failed to create secrets file %s: %v", path, err) + return "", err + } + + secrets, err := s.getYamlStruct(path) + if err != nil { + log.Printf("[ERROR] Failed to parse YAML file %s: %v", path, err) + return "", err + } + + var old_value string = "" + + // If the value exists update it + for idx, k := range secrets.Secrets { + if k.Key == key { + secrets.Secrets[idx].Value = value + old_value = k.Value + } + } + + // If the value doesn't exist create it + if old_value == "" { + secrets.Secrets = append( + secrets.Secrets, + Secret{ + Key: key, + Value: value, + }, + ) + } + + err = s.setYamlStruct(path, secrets) + if err != nil { + log.Printf("[ERROR] Failed to update YAML file %s: %v", path, err) + return "", err + } + + return old_value, nil +} + +func (s DebugFileSecrets) GetValue(key string) (string, error) { + path := s.Path + + secrets, err := s.getYamlStruct(path) + if err != nil { + log.Printf("[ERROR] Failed to parse YAML file %s: %v", path, err) + return "", err + } + + for _, k := range secrets.Secrets { + if k.Key == key { + return k.Value, nil + } + } + + return "", nil +} + +func (s DebugFileSecrets) setYamlStruct(path string, secrets Secrets) error { + data, err := yaml.Marshal(secrets) + if err != nil { + fmt.Printf("[ERROR] Failed to parse file YAML %s: %v", path, err) + return err + } + + file, err := os.OpenFile(path, os.O_RDWR, DEFAULT_PERMS) + if err != nil { + log.Printf("[ERROR] Failed to open secrets file %s: %v", path, err) + return err + } + + log.Printf("data: %s\n", data) + + _, err = file.Write(data) + if err != nil { + log.Printf("[ERROR] Failed to read file %s: %v", path, err) + return err + } + + return nil +} + +func (s DebugFileSecrets) getYamlStruct(path string) (Secrets, error) { + file, err := os.OpenFile(path, os.O_RDWR, DEFAULT_PERMS) + if err != nil { + log.Printf("[ERROR] Failed to open secrets file %s: %v", path, err) + return Secrets{}, err + } + + data := make([]byte, MAX_FILE_SIZE) + n, err := file.Read(data) + if err != nil { + log.Printf("[ERROR] Failed to read file %s: %v", path, err) + return Secrets{}, err + } + + data = data[0:n] + + var secrets Secrets + err = yaml.Unmarshal(data, &secrets) + if err != nil { + fmt.Printf("[ERROR] Failed to parse file YAML %s: %v", path, err) + return Secrets{}, err + } + + return secrets, nil +} + +func (s DebugFileSecrets) createSecretsFile() (string, error) { + _, err := os.Stat(s.Path) + if errors.Is(err, os.ErrNotExist) { + // Create file + f, err := os.OpenFile(s.Path, os.O_CREATE, DEFAULT_PERMS) + if err != nil { + log.Printf("[ERROR] Failed to create file %s\n", s.Path) + return s.Path, err + } + defer f.Close() + + // Write empty struct to file + err = s.setYamlStruct(s.Path, Secrets{}) + if err != nil { + log.Printf("[ERROR] Failed to set yaml struct") + return s.Path, err + } + } + return s.Path, nil +} + +// func checkFileExists(filePath string) bool { +// _, error := os.Stat(filePath) +// //return !os.IsNotExist(err) +// return !errors.Is(error, os.ErrNotExist) +// } diff --git a/tavern/internal/secrets/debug_file_test.go b/tavern/internal/secrets/debug_file_test.go new file mode 100644 index 000000000..eb7d4d74d --- /dev/null +++ b/tavern/internal/secrets/debug_file_test.go @@ -0,0 +1,93 @@ +package secrets_test + +import ( + "log" + "os" + "path" + "testing" + + "github.com/stretchr/testify/assert" + "realm.pub/tavern/internal/secrets" +) + +func createTestSecrets(t *testing.T) string { + // TODO: How do I clean up this test file 🫠 + tmpDir := t.TempDir() + secretsPath := path.Join(tmpDir, "secrets.yaml") + data := []byte(` +secrets: + - key: TAVERN_PRIVATE_KEY + value: Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE= + - key: super_secret_test_data + value: hello world! +`) + err := os.WriteFile(secretsPath, data, 0644) + if err != nil { + log.Fatalf("Failed to write test file %s: %v", secretsPath, err) + } + + return secretsPath +} + +func TestGetSecrets(t *testing.T) { + path := createTestSecrets(t) + defer os.Remove(path) + + secretsManager := secrets.NewDebugFileSecrets(path) + res, err := secretsManager.GetValue("super_secret_test_data") + assert.Nil(t, err) + assert.Equal(t, "hello world!", res) + + res, err = secretsManager.GetValue("TAVERN_PRIVATE_KEY") + assert.Nil(t, err) + assert.Equal(t, "Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE=", res) +} + +func TestSetSecretsAdd(t *testing.T) { + path := createTestSecrets(t) + defer os.Remove(path) + + secretsManager := secrets.NewDebugFileSecrets(path) + res, err := secretsManager.SetValue("WOAH!", "This works!") + assert.Nil(t, err) + assert.Equal(t, "", res) + + res, err = secretsManager.GetValue("WOAH!") + assert.Nil(t, err) + assert.Equal(t, "This works!", res) + + // --- + + res, err = secretsManager.SetValue("WOAH!", "This works too!") + assert.Nil(t, err) + assert.Equal(t, "This works!", res) + + res, err = secretsManager.GetValue("WOAH!") + assert.Nil(t, err) + assert.Equal(t, "This works too!", res) + + // --- + + res, err = secretsManager.GetValue("TAVERN_PRIVATE_KEY") + assert.Nil(t, err) + assert.Equal(t, "Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE=", res) +} + +func TestSetSecretsNew(t *testing.T) { + tmpDir := t.TempDir() + path := path.Join(tmpDir, "secrets.yaml") + defer os.Remove(path) + + secretsManager := secrets.NewDebugFileSecrets(path) + res, err := secretsManager.GetValue("super_secret_test_data") + // Make sure this fails + assert.NotNil(t, err) + + res, err = secretsManager.SetValue("super_secret_test_data", "now this will work") + assert.Nil(t, err) + assert.Equal(t, "", res) + + res, err = secretsManager.GetValue("super_secret_test_data") + assert.Nil(t, err) + assert.Equal(t, "now this will work", res) +} diff --git a/tavern/internal/secrets/secrets.go b/tavern/internal/secrets/secrets.go new file mode 100644 index 000000000..99c765aed --- /dev/null +++ b/tavern/internal/secrets/secrets.go @@ -0,0 +1,7 @@ +package secrets + +type SecretsManager interface { + GetName() string + SetValue(string, string) (string, error) + GetValue(string) (string, error) +} From d2f4b52d6c269b72f83063fb2159cc7cdfd0450c Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 1 Jul 2024 00:55:44 +0000 Subject: [PATCH 038/141] Remove static key --- tavern/config.go | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/tavern/config.go b/tavern/config.go index 80df283dd..c01ca4db2 100644 --- a/tavern/config.go +++ b/tavern/config.go @@ -22,13 +22,6 @@ import ( const REDACTED = "[REDACTED]" -// !!!! DANGER !!!!! -// This is the default static key set to ensure compatability between server and client -// in debug builds. This key must be changed in order to protect data. We're still in the -// process of implementing app layer crypto and this is temporary. Do not rely on the -// app layer crypto without changing this default. -const EnvImixEncryptKeyDefault = "I Don't care how small the room is I cast fireball" - var ( // EnvEnableTestData if set will populate the database with test data. // EnvEnableTestRunAndExit will start the application, but exit immediately after. @@ -206,13 +199,6 @@ func (cfg *Config) IsTestRunAndExitEnabled() bool { return EnvEnableTestRunAndExit.String() != "" } -func (cfg *Config) GetEncryptKey() []byte { - if EnvImixEncryptKey.String() == REDACTED { - return []byte(EnvImixEncryptKeyDefault) - } - return []byte(EnvImixEncryptKey.String()) -} - // ConfigureHTTPServer enables the configuration of the Tavern HTTP server. The endpoint field will be // overwritten with Tavern's HTTP handler when Tavern is run. func ConfigureHTTPServerFromEnv(options ...func(*http.Server)) func(*Config) { From 50c9de7ed6c2c64077ce9cd5a81bc9506602677b Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 1 Jul 2024 00:56:11 +0000 Subject: [PATCH 039/141] Remove static key --- tavern/config.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/tavern/config.go b/tavern/config.go index c01ca4db2..83c4d45bf 100644 --- a/tavern/config.go +++ b/tavern/config.go @@ -73,9 +73,6 @@ var ( // EnvEnableMetrics enables the /metrics endpoint and HTTP server. It is unauthenticated and should be used carefully. EnvEnablePProf = EnvString{"ENABLE_PPROF", ""} EnvEnableMetrics = EnvString{"ENABLE_METRICS", ""} - - // EnvImixEncryptKey is the secret key used to encrypt app layer communication - EnvImixEncryptKey = EnvString{"IMIX_ENCRYPT_KEY", REDACTED} ) // Config holds information that controls the behaviour of Tavern From 7a8ff5e06f12ca125075905b5785250c8ff27eb9 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 1 Jul 2024 00:58:29 +0000 Subject: [PATCH 040/141] Remove static key bits. --- tavern/app.go | 1 - tavern/config.go | 2 -- terraform/main.tf | 16 ---------------- 3 files changed, 19 deletions(-) diff --git a/tavern/app.go b/tavern/app.go index ea141b04f..068268792 100644 --- a/tavern/app.go +++ b/tavern/app.go @@ -326,7 +326,6 @@ func generate_key_pair() (*ecdh.PublicKey, *ecdh.PrivateKey) { func newGRPCHandler(client *ent.Client, grpcShellMux *stream.Mux) http.Handler { public_key, priv_key := generate_key_pair() log.Println("[INFO] Public key: ", base64.StdEncoding.EncodeToString(public_key.Bytes())) - log.Println("[INFO] Private key: ", base64.StdEncoding.EncodeToString(priv_key.Bytes())) c2srv := c2.New(client, grpcShellMux) xchacha := cryptocodec.StreamDecryptCodec{ Csvc: cryptocodec.NewCryptoSvc(priv_key), diff --git a/tavern/config.go b/tavern/config.go index 83c4d45bf..54531df05 100644 --- a/tavern/config.go +++ b/tavern/config.go @@ -20,8 +20,6 @@ import ( "realm.pub/tavern/tomes" ) -const REDACTED = "[REDACTED]" - var ( // EnvEnableTestData if set will populate the database with test data. // EnvEnableTestRunAndExit will start the application, but exit immediately after. diff --git a/terraform/main.tf b/terraform/main.tf index c740acfa1..0ee9cfa21 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -88,18 +88,6 @@ variable "enable_metrics" { description = "Enable prometheus sidecar and Tavern metrics collection" default = false } -// !!!! DANGER !!!!! -// This is the default static key set to ensure compatability between server and client -// in debug builds. This key must be changed in order to protect data. We're still in the -// process of implementing app layer crypto and this is temporary. Do not rely on the -// app layer crypto without changing this default. -variable "imix_encrypt_key" { - type = string - description = "The encryption key tavern and imix should use to talk to each other" - sensitive = true - default = "I Don't care how small the room is I cast fireball" -} - provider "google" { project = var.gcp_project @@ -211,10 +199,6 @@ resource "google_cloud_run_service" "tavern" { name = "ENABLE_METRICS" value = var.enable_metrics ? "1" : "" } - env { - name = "IMIX_ENCRYPT_KEY" - value = var.imix_encrypt_key - } } // Only create prometheus sidecar if metrics enabled From 7abe24c4ce3cb6acf085cb0e276b7952c2b2e616 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 1 Jul 2024 01:06:14 +0000 Subject: [PATCH 041/141] Add launch.json --- .github/workflows/tests.yml | 1 + .vscode/launch.json | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 .vscode/launch.json diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1eb7d7208..3b65662bf 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -9,6 +9,7 @@ on: env: CARGO_TERM_COLOR: always + SERVER_PUBKEY: "pR56vDJZb9b3BL3ZvCXIvgK0r2vCk7FiZ1RjeEhJVyU=" jobs: tavern: diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..fc71cbbb4 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,10 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "env": { + "SERVER_PUBKEY": "pR56vDJZb9b3BL3ZvCXIvgK0r2vCk7FiZ1RjeEhJVyU=" + }, + } + ] +} From 6bf6a5b3411444faef4966f174e6779aa8f7cde0 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 2 Jul 2024 01:52:39 +0000 Subject: [PATCH 042/141] Fix env! error --- .vscode/launch.json | 10 ---------- .vscode/settings.json | 3 +++ 2 files changed, 3 insertions(+), 10 deletions(-) delete mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index fc71cbbb4..000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "env": { - "SERVER_PUBKEY": "pR56vDJZb9b3BL3ZvCXIvgK0r2vCk7FiZ1RjeEhJVyU=" - }, - } - ] -} diff --git a/.vscode/settings.json b/.vscode/settings.json index 4fad2d189..f8e40f873 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,6 +3,9 @@ "--profile", "rust-analyzer" ], + "rust-analyzer.server.extraEnv": { + "SERVER_PUBKEY": "[OVERRIDE THIS VARIABLE]" + }, "rust-analyzer.check.command": "clippy", "rust-analyzer.showUnlinkedFileNotification": false, } From 3ae7a40f2a3b3a645cd39ef4e038fe07bc2cf6ec Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Thu, 4 Jul 2024 00:28:38 +0000 Subject: [PATCH 043/141] Stubbed out GCP KMS --- go.mod | 43 +++++++++--------- go.sum | 60 +++++++++++++++++++++++++ tavern/internal/secrets/gcp.go | 81 ++++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+), 20 deletions(-) create mode 100644 tavern/internal/secrets/gcp.go diff --git a/go.mod b/go.mod index fcd6f8c29..b3e8c2889 100644 --- a/go.mod +++ b/go.mod @@ -13,21 +13,24 @@ require ( github.com/hashicorp/go-multierror v1.1.1 github.com/mattn/go-sqlite3 v1.14.16 github.com/prometheus/client_golang v1.18.0 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 github.com/urfave/cli v1.22.5 github.com/vektah/gqlparser/v2 v2.5.10 - golang.org/x/crypto v0.21.0 - golang.org/x/net v0.22.0 - golang.org/x/oauth2 v0.18.0 - golang.org/x/sync v0.6.0 - google.golang.org/grpc v1.62.1 - google.golang.org/protobuf v1.33.0 + golang.org/x/crypto v0.24.0 + golang.org/x/net v0.26.0 + golang.org/x/oauth2 v0.21.0 + golang.org/x/sync v0.7.0 + google.golang.org/grpc v1.64.0 + google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v3 v3.0.1 ) require ( - cloud.google.com/go/iam v1.1.6 // indirect - cloud.google.com/go/pubsub v1.37.0 // indirect + cloud.google.com/go/auth v0.6.1 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect + cloud.google.com/go/iam v1.1.9 // indirect + cloud.google.com/go/pubsub v1.40.0 // indirect + cloud.google.com/go/secretmanager v1.13.3 // indirect dario.cat/mergo v1.0.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect @@ -44,7 +47,7 @@ require ( github.com/google/s2a-go v0.1.7 // indirect github.com/google/wire v0.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.2 // indirect + github.com/googleapis/gax-go/v2 v2.12.5 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect @@ -59,16 +62,16 @@ require ( go.opentelemetry.io/otel/trace v1.24.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect - google.golang.org/api v0.169.0 // indirect - google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240311173647-c811ad7063a7 // indirect + google.golang.org/api v0.187.0 // indirect + google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240624140628-dc46fd24d27d // indirect gopkg.in/warnings.v0 v0.1.2 // indirect ) require ( ariga.io/atlas v0.14.2 // indirect - cloud.google.com/go/compute v1.25.0 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/compute v1.27.1 // indirect + cloud.google.com/go/compute/metadata v0.3.0 // indirect github.com/agext/levenshtein v1.2.3 // indirect github.com/agnivade/levenshtein v1.1.1 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect @@ -97,10 +100,10 @@ require ( github.com/zclconf/go-cty v1.14.1 // indirect gocloud.dev v0.37.0 golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect - golang.org/x/mod v0.14.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/tools v0.17.0 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240311173647-c811ad7063a7 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d // indirect ) diff --git a/go.sum b/go.sum index 48f595113..b8c28db0f 100644 --- a/go.sum +++ b/go.sum @@ -2,14 +2,35 @@ ariga.io/atlas v0.14.2 h1:efxCuSGnDuhx7xm4JaqImR6xd+PqyizgGy5u/XUEI/g= ariga.io/atlas v0.14.2/go.mod h1:isZrlzJ5cpoCoKFoY9knZug7Lq4pP1cm8g3XciLZ0Pw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= +cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14= +cloud.google.com/go/auth v0.6.1 h1:T0Zw1XM5c1GlpN2HYr2s+m3vr1p2wy+8VN+Z1FKxW38= +cloud.google.com/go/auth v0.6.1/go.mod h1:eFHG7zDzbXHKmjJddFG/rBlcGp6t25SwRUiEQSlO4x4= +cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4= +cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= cloud.google.com/go/compute v1.25.0 h1:H1/4SqSUhjPFE7L5ddzHOfY2bCAvjwNRZPNl6Ni5oYU= cloud.google.com/go/compute v1.25.0/go.mod h1:GR7F0ZPZH8EhChlMo9FkLd7eUTwEymjqQagxzilIxIE= +cloud.google.com/go/compute v1.27.0 h1:EGawh2RUnfHT5g8f/FX3Ds6KZuIBC77hZoDrBvEZw94= +cloud.google.com/go/compute v1.27.0/go.mod h1:LG5HwRmWFKM2C5XxHRiNzkLLXW48WwvyVC0mfWsYPOM= +cloud.google.com/go/compute v1.27.1 h1:0WbBLIPNANheCRZ4h8QhgzjN53KMutbiVBOLtPiVzBU= +cloud.google.com/go/compute v1.27.1/go.mod h1:UVWm+bWKEKoM+PW2sZycP1Jgk3NhKwR2Iy2Cnp/G40I= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= +cloud.google.com/go/iam v1.1.8 h1:r7umDwhj+BQyz0ScZMp4QrGXjSTI3ZINnpgU2nlB/K0= +cloud.google.com/go/iam v1.1.8/go.mod h1:GvE6lyMmfxXauzNq8NbgJbeVQNspG+tcdL/W8QO1+zE= +cloud.google.com/go/iam v1.1.9 h1:oSkYLVtVme29uGYrOcKcvJRht7cHJpYD09GM9JaR0TE= +cloud.google.com/go/iam v1.1.9/go.mod h1:Nt1eDWNYH9nGQg3d/mY7U1hvfGmsaG9o/kLGoLoLXjQ= cloud.google.com/go/pubsub v1.37.0 h1:0uEEfaB1VIJzabPpwpZf44zWAKAme3zwKKxHk7vJQxQ= cloud.google.com/go/pubsub v1.37.0/go.mod h1:YQOQr1uiUM092EXwKs56OPT650nwnawc+8/IjoUeGzQ= +cloud.google.com/go/pubsub v1.39.0 h1:qt1+S6H+wwW8Q/YvDwM8lJnq+iIFgFEgaD/7h3lMsAI= +cloud.google.com/go/pubsub v1.39.0/go.mod h1:FrEnrSGU6L0Kh3iBaAbIUM8KMR7LqyEkMboVxGXCT+s= +cloud.google.com/go/pubsub v1.40.0 h1:0LdP+zj5XaPAGtWr2V6r88VXJlmtaB/+fde1q3TU8M0= +cloud.google.com/go/pubsub v1.40.0/go.mod h1:BVJI4sI2FyXp36KFKvFwcfDRDfR8MiLT8mMhmIhdAeA= +cloud.google.com/go/secretmanager v1.13.3 h1:VqUVYY3U6uFXOhPdZgAoZH9m8E6p7eK02TsDRj2SBf4= +cloud.google.com/go/secretmanager v1.13.3/go.mod h1:e45+CxK0w6GaL4hS+KabgQskl4RdSS30b+HRf0TH0kk= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= entgo.io/contrib v0.4.5 h1:BFaOHwFLE8WZjVJadP0XHCIaxgcC1BAtUvAyw7M/GHk= @@ -143,6 +164,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfF github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.12.2 h1:mhN09QQW1jEWeMF74zGR81R30z4VJzjZsfkUhuHF+DA= github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= +github.com/googleapis/gax-go/v2 v2.12.5 h1:8gw9KZK8TiVKB6q3zHY3SBzLnrGp6HQjyfYBYGmXdxA= +github.com/googleapis/gax-go/v2 v2.12.5/go.mod h1:BUDKcWo+RaKq5SC9vVYL0wLADa3VcfswbOMMRmB9H3E= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -205,6 +228,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -212,6 +236,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU= github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vektah/gqlparser/v2 v2.5.10 h1:6zSM4azXC9u4Nxy5YmdmGu4uKamfwsdKTwp5zsEealU= @@ -236,6 +262,7 @@ go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= +go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= gocloud.dev v0.37.0 h1:XF1rN6R0qZI/9DYjN16Uy0durAmSlf58DHOcb28GPro= @@ -250,6 +277,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= @@ -261,6 +290,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -279,9 +310,13 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -290,6 +325,8 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -311,6 +348,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -320,6 +359,7 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -332,6 +372,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -345,12 +387,16 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= google.golang.org/api v0.169.0 h1:QwWPy71FgMWqJN/l6jVlFHUa29a7dcUy02I8o799nPY= google.golang.org/api v0.169.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg= +google.golang.org/api v0.187.0 h1:Mxs7VATVC2v7CY+7Xwm4ndkX71hpElcvx0D1Ji/p1eo= +google.golang.org/api v0.187.0/go.mod h1:KIHlTc4x7N7gKKuVsdmfBXN13yEEWXWFURWY6SBp2gk= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= @@ -360,10 +406,20 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 h1:ImUcDPHjTrAqNhlOkSocDLfG9rrNHH7w7uoKWPaWZ8s= google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7/go.mod h1:/3XmxOjePkvmKrHuBy4zNFw7IzxJXtAgdpXi8Ll990U= +google.golang.org/genproto v0.0.0-20240624140628-dc46fd24d27d h1:PksQg4dV6Sem3/HkBX+Ltq8T0ke0PKIRBNBatoDTVls= +google.golang.org/genproto v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:s7iA721uChleev562UJO2OYB0PPT9CMFjV+Ce7VJH5M= +google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094 h1:6whtk83KtD3FkGrVb2hFXuQ+ZMbCNdakARIn/aHMmG8= +google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094/go.mod h1:Zs4wYw8z1zr6RNF4cwYb31mvN/EGaKAdQjNCF3DW6K4= google.golang.org/genproto/googleapis/api v0.0.0-20240311173647-c811ad7063a7 h1:oqta3O3AnlWbmIE3bFnWbu4bRxZjfbWCp0cKSuZh01E= google.golang.org/genproto/googleapis/api v0.0.0-20240311173647-c811ad7063a7/go.mod h1:VQW3tUculP/D4B+xVCo+VgSq8As6wA9ZjHl//pmk+6s= +google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4 h1:MuYw1wJzT+ZkybKfaOXKp5hJiZDn2iHaXRw0mRYdHSc= +google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4/go.mod h1:px9SlOOZBg1wM1zdnr8jEL4CNGUBZ+ZKYtNPApNQc4c= +google.golang.org/genproto/googleapis/api v0.0.0-20240624140628-dc46fd24d27d h1:Aqf0fiIdUQEj0Gn9mKFFXoQfTTEaNopWpfVyYADxiSg= +google.golang.org/genproto/googleapis/api v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:Od4k8V1LQSizPRUK4OzZ7TBE/20k+jPczUDAEyvn69Y= google.golang.org/genproto/googleapis/rpc v0.0.0-20240311173647-c811ad7063a7 h1:8EeVk1VKMD+GD/neyEHGmz7pFblqPjHoi+PGQIlLx2s= google.golang.org/genproto/googleapis/rpc v0.0.0-20240311173647-c811ad7063a7/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d h1:k3zyW3BYYR30e8v3x0bTDdE9vpYFjZHK+HcyqkrppWk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= @@ -371,6 +427,8 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= +google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -384,6 +442,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/tavern/internal/secrets/gcp.go b/tavern/internal/secrets/gcp.go new file mode 100644 index 000000000..7fcbba402 --- /dev/null +++ b/tavern/internal/secrets/gcp.go @@ -0,0 +1,81 @@ +package secrets + +import ( + "context" + "fmt" + "log" + + secretmanager "cloud.google.com/go/secretmanager/apiv1" + "cloud.google.com/go/secretmanager/apiv1/secretmanagerpb" +) + +type Gcp struct { + Name string + projectID string +} + +// GetName implements SecretsManager. +func (g Gcp) GetName() string { + return g.Name +} + +// GetValue implements SecretsManager. +func (g Gcp) GetValue(string) (string, error) { + panic("unimplemented") +} + +// SetValue implements SecretsManager. +func (g Gcp) SetValue(key string, value string) (string, error) { + // GCP project in which to store secrets in Secret Manager. + projectID := "your-project-id" + + // Create the client. + ctx := context.Background() + client, err := secretmanager.NewClient(ctx) + if err != nil { + log.Fatalf("failed to setup client: %v", err) + } + defer client.Close() + + // Create the request to create the secret. + createSecretReq := &secretmanagerpb.CreateSecretRequest{ + Parent: fmt.Sprintf("projects/%s", projectID), + SecretId: "my-secret", + Secret: &secretmanagerpb.Secret{ + Replication: &secretmanagerpb.Replication{ + Replication: &secretmanagerpb.Replication_Automatic_{ + Automatic: &secretmanagerpb.Replication_Automatic{}, + }, + }, + }, + } + + secret, err := client.CreateSecret(ctx, createSecretReq) + if err != nil { + log.Fatalf("failed to create secret: %v", err) + } + + // Declare the payload to store. + payload := []byte("my super secret data") + + // Build the request. + addSecretVersionReq := &secretmanagerpb.AddSecretVersionRequest{ + Parent: secret.Name, + Payload: &secretmanagerpb.SecretPayload{ + Data: payload, + }, + } + + // Call the API. + version, err := client.AddSecretVersion(ctx, addSecretVersionReq) + if err != nil { + log.Fatalf("failed to add secret version: %v", err) + } + +} + +func NewGcp() SecretsManager { + return Gcp{ + Name: "Gcp", + } +} From 6128048373fb759b10ded7620a4d0b782146e1e6 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Sun, 7 Jul 2024 19:13:42 +0000 Subject: [PATCH 044/141] Implement gcp secret manager --- tavern/internal/secrets/debug_file_test.go | 7 +- tavern/internal/secrets/gcp.go | 127 +++++++++++++++++---- tavern/internal/secrets/gcp_test.go | 37 ++++++ 3 files changed, 145 insertions(+), 26 deletions(-) create mode 100644 tavern/internal/secrets/gcp_test.go diff --git a/tavern/internal/secrets/debug_file_test.go b/tavern/internal/secrets/debug_file_test.go index eb7d4d74d..d81fed992 100644 --- a/tavern/internal/secrets/debug_file_test.go +++ b/tavern/internal/secrets/debug_file_test.go @@ -29,7 +29,7 @@ secrets: return secretsPath } -func TestGetSecrets(t *testing.T) { +func TestGetSecretsFile(t *testing.T) { path := createTestSecrets(t) defer os.Remove(path) @@ -43,7 +43,7 @@ func TestGetSecrets(t *testing.T) { assert.Equal(t, "Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE=", res) } -func TestSetSecretsAdd(t *testing.T) { +func TestSetSecretsAddFile(t *testing.T) { path := createTestSecrets(t) defer os.Remove(path) @@ -73,7 +73,7 @@ func TestSetSecretsAdd(t *testing.T) { assert.Equal(t, "Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE=", res) } -func TestSetSecretsNew(t *testing.T) { +func TestSetSecretsNewFile(t *testing.T) { tmpDir := t.TempDir() path := path.Join(tmpDir, "secrets.yaml") defer os.Remove(path) @@ -82,6 +82,7 @@ func TestSetSecretsNew(t *testing.T) { res, err := secretsManager.GetValue("super_secret_test_data") // Make sure this fails assert.NotNil(t, err) + assert.Equal(t, "", res) res, err = secretsManager.SetValue("super_secret_test_data", "now this will work") assert.Nil(t, err) diff --git a/tavern/internal/secrets/gcp.go b/tavern/internal/secrets/gcp.go index 7fcbba402..66ab2e579 100644 --- a/tavern/internal/secrets/gcp.go +++ b/tavern/internal/secrets/gcp.go @@ -2,16 +2,23 @@ package secrets import ( "context" + "encoding/json" + "errors" "fmt" "log" + "strings" secretmanager "cloud.google.com/go/secretmanager/apiv1" "cloud.google.com/go/secretmanager/apiv1/secretmanagerpb" + "golang.org/x/oauth2/google" + "google.golang.org/api/compute/v1" ) type Gcp struct { Name string projectID string + client *secretmanager.Client + clientctx context.Context } // GetName implements SecretsManager. @@ -20,27 +27,56 @@ func (g Gcp) GetName() string { } // GetValue implements SecretsManager. -func (g Gcp) GetValue(string) (string, error) { - panic("unimplemented") +func (g Gcp) GetValue(key string) (string, error) { + // name := "projects/my-project/secrets/my-secret" + name := fmt.Sprintf("projects/%s/secrets/%s/versions/latest", g.projectID, key) + + // Build the request. + accessRequest := &secretmanagerpb.AccessSecretVersionRequest{ + Name: name, + } + + // Call the API. + result, err := g.client.AccessSecretVersion(g.clientctx, accessRequest) + if err != nil { + log.Printf("[ERROR] failed to access secret version: %v\n", err) + return "", err + } + + value := string(result.Payload.Data) + + return value, nil } -// SetValue implements SecretsManager. -func (g Gcp) SetValue(key string, value string) (string, error) { - // GCP project in which to store secrets in Secret Manager. - projectID := "your-project-id" +type credentialsJson struct { + ProjectID string `json:"quota_project_id"` +} - // Create the client. - ctx := context.Background() - client, err := secretmanager.NewClient(ctx) +func GetCurrentGcpProject(ctx context.Context) (string, error) { + respMesg, err := google.FindDefaultCredentials(ctx, compute.ComputeScope) if err != nil { - log.Fatalf("failed to setup client: %v", err) + return "", err } - defer client.Close() - // Create the request to create the secret. - createSecretReq := &secretmanagerpb.CreateSecretRequest{ - Parent: fmt.Sprintf("projects/%s", projectID), - SecretId: "my-secret", + // respMesg.ProjectID can be empty so instead we grab from the creds JSON file + credJSON := credentialsJson{} + err = json.Unmarshal(respMesg.JSON, &credJSON) + if err != nil { + return "", err + } + ProjectID := credJSON.ProjectID + + if ProjectID == "" { + return "", errors.New("project id is empty") + } + + return ProjectID, nil +} + +func (g Gcp) newCreateSecretReq(key string, parent string) secretmanagerpb.CreateSecretRequest { + return secretmanagerpb.CreateSecretRequest{ + Parent: parent, + SecretId: key, Secret: &secretmanagerpb.Secret{ Replication: &secretmanagerpb.Replication{ Replication: &secretmanagerpb.Replication_Automatic_{ @@ -49,33 +85,78 @@ func (g Gcp) SetValue(key string, value string) (string, error) { }, }, } +} - secret, err := client.CreateSecret(ctx, createSecretReq) +// SetValue implements SecretsManager. +func (g Gcp) SetValue(key string, value string) (string, error) { + // Create the request to create the secret. + parent := fmt.Sprintf("projects/%s", g.projectID) + createSecretReq := g.newCreateSecretReq(key, parent) + + old_value := "" + _, err := g.client.CreateSecret(g.clientctx, &createSecretReq) if err != nil { - log.Fatalf("failed to create secret: %v", err) + if !strings.Contains(err.Error(), "code = AlreadyExists") { + log.Printf("[ERROR] Failed to create secret: %v\n", err) + return "", err + } else { + tmp, err := g.GetValue(key) + if err != nil { + log.Printf("[ERROR] Failed to get old secret: %v\n", err) + return "", err + } + old_value = tmp + } } // Declare the payload to store. - payload := []byte("my super secret data") + path := fmt.Sprintf("%s/secrets/%s", parent, key) + payload := []byte(value) // Build the request. addSecretVersionReq := &secretmanagerpb.AddSecretVersionRequest{ - Parent: secret.Name, + Parent: path, Payload: &secretmanagerpb.SecretPayload{ Data: payload, }, } // Call the API. - version, err := client.AddSecretVersion(ctx, addSecretVersionReq) + version, err := g.client.AddSecretVersion(g.clientctx, addSecretVersionReq) if err != nil { log.Fatalf("failed to add secret version: %v", err) } + log.Printf("version: %v\n", version) + return old_value, nil } -func NewGcp() SecretsManager { - return Gcp{ - Name: "Gcp", +func NewGcp(projectID string) (SecretsManager, error) { + // GCP project in which to store secrets in Secret Manager. + ctx := context.Background() + + // If unset try to figure out the current GCP + if projectID == "" { + tmp, err := GetCurrentGcpProject(ctx) + projectID = tmp + if err != nil { + fmt.Printf("[ERROR] Failed to get current project ID: %v\n", err) + return nil, err + } + } + fmt.Printf("[DEBUG] Using projectID: %s\n", projectID) + + // Create the client. + client, err := secretmanager.NewClient(ctx) + if err != nil { + log.Printf("[ERROR] Failed to setup client: %v\n", err) + return nil, err } + + return Gcp{ + Name: "Gcp", + projectID: projectID, + client: client, + clientctx: ctx, + }, nil } diff --git a/tavern/internal/secrets/gcp_test.go b/tavern/internal/secrets/gcp_test.go new file mode 100644 index 000000000..616131e69 --- /dev/null +++ b/tavern/internal/secrets/gcp_test.go @@ -0,0 +1,37 @@ +package secrets_test + +// No way to test this in CI but worked in dev + +// import ( +// "testing" + +// "github.com/stretchr/testify/assert" +// "realm.pub/tavern/internal/secrets" +// ) + +// func TestSetSecretsGcp(t *testing.T) { +// test_key := "super_secret_test_data" +// // Create manager +// secretsManager, err := secrets.NewGcp("") +// assert.NotNil(t, secretsManager) +// assert.Nil(t, err) +// // Get a non existent value +// res, err := secretsManager.GetValue(test_key) +// assert.NotNil(t, err) +// assert.Equal(t, "", res) + +// // Create a value +// res, err = secretsManager.SetValue(test_key, "This should work") +// assert.Nil(t, err) +// assert.Equal(t, "", res) + +// // Update the value +// res, err = secretsManager.SetValue(test_key, "This should work too") +// assert.Nil(t, err) +// assert.Equal(t, "This should work", res) + +// // Get the value +// res, err = secretsManager.GetValue(test_key) +// assert.Nil(t, err) +// assert.Equal(t, "This should work too", res) +// } From 7bf6ff5a00a4a63b3a741be8be807b193552f304 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Sun, 7 Jul 2024 21:33:01 +0000 Subject: [PATCH 045/141] switch to []byte --- .vscode/settings.json | 2 +- implants/lib/pb/src/xchacha.rs | 22 +++++----- tavern/app.go | 47 ++++++++++++++++++++-- tavern/internal/secrets/debug_file.go | 39 +++++++++--------- tavern/internal/secrets/debug_file_test.go | 40 +++++++++--------- tavern/internal/secrets/gcp.go | 35 +++++++--------- tavern/internal/secrets/gcp_test.go | 12 +++--- tavern/internal/secrets/secrets.go | 4 +- 8 files changed, 118 insertions(+), 83 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index f8e40f873..376f8d907 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,7 +4,7 @@ "rust-analyzer" ], "rust-analyzer.server.extraEnv": { - "SERVER_PUBKEY": "[OVERRIDE THIS VARIABLE]" + "IMIX_SERVER_PUBKEY": "[OVERRIDE THIS VARIABLE]" }, "rust-analyzer.check.command": "clippy", "rust-analyzer.showUnlinkedFileNotification": false, diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index d470fbebf..720d506d0 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -17,7 +17,7 @@ use tonic::{ }; use x25519_dalek::{EphemeralSecret, PublicKey}; -const SERVER_PUBKEY_STR: &str = env!("SERVER_PUBKEY"); +const SERVER_PUBKEY_STR: &str = env!("IMIX_SERVER_PUBKEY"); const SERVER_PUBKEY: [u8; 32] = const_decode::Base64.decode(SERVER_PUBKEY_STR.as_bytes()); // ------------ @@ -42,15 +42,9 @@ fn get_key(pub_key: [u8; 32]) -> Result<[u8; 32]> { // ------------ -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct ChaChaSvc {} -impl Default for ChaChaSvc { - fn default() -> Self { - Self {} - } -} - #[derive(Debug, Clone)] pub struct ChachaCodec(PhantomData<(T, U)>, ChaChaSvc); @@ -131,8 +125,8 @@ where }; // Write pubkey + nonce + cipher text - buf.writer().write_all(client_public.as_bytes()); - buf.writer().write_all(nonce.as_slice()); + buf.writer().write_all(client_public.as_bytes())?; + buf.writer().write_all(nonce.as_slice())?; buf.writer().write_all(ciphertext.as_slice())?; Ok(()) @@ -142,6 +136,8 @@ where // --- // const DEFAULT_CODEC_BUFFER_SIZE: usize = 8 * 1024; +const PUBKEY_LEN: usize = 32; +const NONCE_LEN: usize = 24; #[derive(Debug)] pub struct ChachaDecrypt(PhantomData<(T, U)>, ChaChaSvc); @@ -174,17 +170,17 @@ where .map_err(from_anyhow_error)?; let client_public = buf - .get(0..32) + .get(0..PUBKEY_LEN) .context("Input buffer doesn't have enough bytes for public key") .map_err(from_anyhow_error)?; let nonce = buf - .get(32..56) + .get(PUBKEY_LEN..PUBKEY_LEN + NONCE_LEN) .context("Input buffer doesn't have enough bytes for nonce") .map_err(from_anyhow_error)?; let ciphertext = buf - .get(56..) + .get(PUBKEY_LEN + NONCE_LEN..) .context("Input buffer doesn't have enough bytes for ciphertext") .map_err(from_anyhow_error)?; diff --git a/tavern/app.go b/tavern/app.go index 068268792..0523230fa 100644 --- a/tavern/app.go +++ b/tavern/app.go @@ -5,6 +5,7 @@ import ( "crypto/ecdh" "crypto/ed25519" "crypto/rand" + "crypto/x509" "encoding/base64" "encoding/json" "fmt" @@ -33,6 +34,7 @@ import ( "realm.pub/tavern/internal/graphql" tavernhttp "realm.pub/tavern/internal/http" "realm.pub/tavern/internal/http/stream" + "realm.pub/tavern/internal/secrets" "realm.pub/tavern/internal/www" "realm.pub/tavern/tomes" ) @@ -323,12 +325,51 @@ func generate_key_pair() (*ecdh.PublicKey, *ecdh.PrivateKey) { return public_key, priv_key } +func getKeyPair() (*ecdh.PublicKey, *ecdh.PrivateKey) { + x22519 := ecdh.X25519() + + // secretsManager, err := secrets.NewGcp("") + secretsManager, err := secrets.NewDebugFileSecrets("/etc/realm-secrets.txt") + if err != nil { + log.Printf("[ERROR] Unable to setup secrets manager\n") + } + + // Check if we already have a key + priv_key_string, err := secretsManager.GetValue("tavern_encryption_private_key") + if err != nil { + // Generate a new one if it doesn't exist + priv_key, pub_key := generate_key_pair() + _, err = secretsManager.SetValue("tavern_encryption_private_key", priv_key.Bytes()) + if err != nil { + log.Printf("[ERROR] Unable to set 'tavern_encryption_private_key' using secrets manager: %v", err) + return nil, nil + } + return priv_key, pub_key + } + + // Parse private key bytes + tmp, err := x509.ParsePKCS8PrivateKey(priv_key_string) + if err != nil { + log.Printf("[ERROR] Unable to parse private key %v\n", err) + } + priv_key := tmp.(*ecdh.PrivateKey) + + public_key, err := x22519.NewPublicKey(priv_key.PublicKey().Bytes()) + if err != nil { + log.Printf("[ERROR] Failed to generate public key: %v\n", err) + panic("[ERROR] Failed to generate public key") + } + + return public_key, priv_key +} + func newGRPCHandler(client *ent.Client, grpcShellMux *stream.Mux) http.Handler { - public_key, priv_key := generate_key_pair() - log.Println("[INFO] Public key: ", base64.StdEncoding.EncodeToString(public_key.Bytes())) + pub, priv := getKeyPair() + log.Println("[INFO] Public key: ", base64.StdEncoding.EncodeToString(pub.Bytes())) + c2srv := c2.New(client, grpcShellMux) xchacha := cryptocodec.StreamDecryptCodec{ - Csvc: cryptocodec.NewCryptoSvc(priv_key), + Csvc: cryptocodec.NewCryptoSvc(priv), } grpcSrv := grpc.NewServer( grpc.ForceServerCodec(xchacha), diff --git a/tavern/internal/secrets/debug_file.go b/tavern/internal/secrets/debug_file.go index 04aee10fd..68bc7da92 100644 --- a/tavern/internal/secrets/debug_file.go +++ b/tavern/internal/secrets/debug_file.go @@ -28,76 +28,79 @@ type DebugFileSecrets struct { Path string } -func NewDebugFileSecrets(path string) SecretsManager { +func NewDebugFileSecrets(path string) (SecretsManager, error) { return DebugFileSecrets{ Name: "DebugFileSecrets", Path: path, - } + }, nil } func (s DebugFileSecrets) GetName() string { return s.Name } -func (s DebugFileSecrets) SetValue(key string, value string) (string, error) { - path, err := s.createSecretsFile() +func (s DebugFileSecrets) SetValue(key string, value []byte) ([]byte, error) { + path, err := s.ensureSecretsFileExist() if err != nil { log.Printf("[ERROR] Failed to create secrets file %s: %v", path, err) - return "", err + return []byte{}, err } secrets, err := s.getYamlStruct(path) if err != nil { log.Printf("[ERROR] Failed to parse YAML file %s: %v", path, err) - return "", err + return []byte{}, err } - var old_value string = "" + var old_value []byte = []byte{} + log.Printf("[ERROR] Before: %v\n", secrets.Secrets) // If the value exists update it for idx, k := range secrets.Secrets { if k.Key == key { - secrets.Secrets[idx].Value = value - old_value = k.Value + secrets.Secrets[idx].Value = string(value) + old_value = []byte(k.Value) } } // If the value doesn't exist create it - if old_value == "" { + if len(old_value) == 0 { secrets.Secrets = append( secrets.Secrets, Secret{ Key: key, - Value: value, + Value: string(value), }, ) } + log.Printf("[ERROR] After: %v\n", secrets.Secrets) err = s.setYamlStruct(path, secrets) if err != nil { log.Printf("[ERROR] Failed to update YAML file %s: %v", path, err) - return "", err + return []byte{}, err } return old_value, nil } -func (s DebugFileSecrets) GetValue(key string) (string, error) { +func (s DebugFileSecrets) GetValue(key string) ([]byte, error) { path := s.Path secrets, err := s.getYamlStruct(path) if err != nil { log.Printf("[ERROR] Failed to parse YAML file %s: %v", path, err) - return "", err + return []byte{}, err } for _, k := range secrets.Secrets { + fmt.Printf("key: %s\n", k) if k.Key == key { - return k.Value, nil + return []byte(k.Value), nil } } - return "", nil + return []byte{}, nil } func (s DebugFileSecrets) setYamlStruct(path string, secrets Secrets) error { @@ -113,8 +116,6 @@ func (s DebugFileSecrets) setYamlStruct(path string, secrets Secrets) error { return err } - log.Printf("data: %s\n", data) - _, err = file.Write(data) if err != nil { log.Printf("[ERROR] Failed to read file %s: %v", path, err) @@ -150,7 +151,7 @@ func (s DebugFileSecrets) getYamlStruct(path string) (Secrets, error) { return secrets, nil } -func (s DebugFileSecrets) createSecretsFile() (string, error) { +func (s DebugFileSecrets) ensureSecretsFileExist() (string, error) { _, err := os.Stat(s.Path) if errors.Is(err, os.ErrNotExist) { // Create file diff --git a/tavern/internal/secrets/debug_file_test.go b/tavern/internal/secrets/debug_file_test.go index d81fed992..10b6a81b8 100644 --- a/tavern/internal/secrets/debug_file_test.go +++ b/tavern/internal/secrets/debug_file_test.go @@ -17,9 +17,9 @@ func createTestSecrets(t *testing.T) string { data := []byte(` secrets: - key: TAVERN_PRIVATE_KEY - value: Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE= + value: !!binary Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE= - key: super_secret_test_data - value: hello world! + value: !!binary NjggNjUgNmMgNmMgNmYgMjAgNzcgNmYgNzIgNmMgNjQgMjE= `) err := os.WriteFile(secretsPath, data, 0644) if err != nil { @@ -33,62 +33,66 @@ func TestGetSecretsFile(t *testing.T) { path := createTestSecrets(t) defer os.Remove(path) - secretsManager := secrets.NewDebugFileSecrets(path) + secretsManager, err := secrets.NewDebugFileSecrets(path) + assert.Nil(t, err) res, err := secretsManager.GetValue("super_secret_test_data") assert.Nil(t, err) - assert.Equal(t, "hello world!", res) + assert.Equal(t, []byte("hello world!"), res) res, err = secretsManager.GetValue("TAVERN_PRIVATE_KEY") assert.Nil(t, err) - assert.Equal(t, "Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE=", res) + assert.Equal(t, []byte("Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE="), res) } func TestSetSecretsAddFile(t *testing.T) { path := createTestSecrets(t) defer os.Remove(path) - secretsManager := secrets.NewDebugFileSecrets(path) - res, err := secretsManager.SetValue("WOAH!", "This works!") + secretsManager, err := secrets.NewDebugFileSecrets(path) + assert.Nil(t, err) + res, err := secretsManager.SetValue("WOAH!", []byte("This works!")) assert.Nil(t, err) - assert.Equal(t, "", res) + assert.Equal(t, []byte{}, res) res, err = secretsManager.GetValue("WOAH!") assert.Nil(t, err) - assert.Equal(t, "This works!", res) + assert.Equal(t, []byte("This works!"), res) // --- - res, err = secretsManager.SetValue("WOAH!", "This works too!") + res, err = secretsManager.SetValue("WOAH!", []byte("This works too!")) assert.Nil(t, err) - assert.Equal(t, "This works!", res) + assert.Equal(t, []byte("This works!"), res) res, err = secretsManager.GetValue("WOAH!") assert.Nil(t, err) - assert.Equal(t, "This works too!", res) + assert.Equal(t, []byte("This works too!"), res) // --- res, err = secretsManager.GetValue("TAVERN_PRIVATE_KEY") assert.Nil(t, err) - assert.Equal(t, "Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE=", res) + assert.Equal(t, []byte("Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE="), res) } func TestSetSecretsNewFile(t *testing.T) { tmpDir := t.TempDir() path := path.Join(tmpDir, "secrets.yaml") defer os.Remove(path) + // path = "/tmp/test-secrets.yaml" - secretsManager := secrets.NewDebugFileSecrets(path) + secretsManager, err := secrets.NewDebugFileSecrets(path) + assert.Nil(t, err) res, err := secretsManager.GetValue("super_secret_test_data") // Make sure this fails assert.NotNil(t, err) - assert.Equal(t, "", res) + assert.Equal(t, []byte{}, res) - res, err = secretsManager.SetValue("super_secret_test_data", "now this will work") + res, err = secretsManager.SetValue("super_secret_test_data", []byte{0x99, 0x99}) assert.Nil(t, err) - assert.Equal(t, "", res) + assert.Equal(t, []byte{}, res) res, err = secretsManager.GetValue("super_secret_test_data") assert.Nil(t, err) - assert.Equal(t, "now this will work", res) + assert.Equal(t, []byte{0x99, 0x99}, res) } diff --git a/tavern/internal/secrets/gcp.go b/tavern/internal/secrets/gcp.go index 66ab2e579..62bbf006c 100644 --- a/tavern/internal/secrets/gcp.go +++ b/tavern/internal/secrets/gcp.go @@ -27,7 +27,7 @@ func (g Gcp) GetName() string { } // GetValue implements SecretsManager. -func (g Gcp) GetValue(key string) (string, error) { +func (g Gcp) GetValue(key string) ([]byte, error) { // name := "projects/my-project/secrets/my-secret" name := fmt.Sprintf("projects/%s/secrets/%s/versions/latest", g.projectID, key) @@ -40,12 +40,10 @@ func (g Gcp) GetValue(key string) (string, error) { result, err := g.client.AccessSecretVersion(g.clientctx, accessRequest) if err != nil { log.Printf("[ERROR] failed to access secret version: %v\n", err) - return "", err + return []byte{}, err } - value := string(result.Payload.Data) - - return value, nil + return result.Payload.Data, nil } type credentialsJson struct { @@ -73,8 +71,11 @@ func GetCurrentGcpProject(ctx context.Context) (string, error) { return ProjectID, nil } -func (g Gcp) newCreateSecretReq(key string, parent string) secretmanagerpb.CreateSecretRequest { - return secretmanagerpb.CreateSecretRequest{ +// SetValue implements SecretsManager. +func (g Gcp) SetValue(key string, value []byte) ([]byte, error) { + // Create the request to create the secret. + parent := fmt.Sprintf("projects/%s", g.projectID) + createSecretReq := secretmanagerpb.CreateSecretRequest{ Parent: parent, SecretId: key, Secret: &secretmanagerpb.Secret{ @@ -85,25 +86,18 @@ func (g Gcp) newCreateSecretReq(key string, parent string) secretmanagerpb.Creat }, }, } -} - -// SetValue implements SecretsManager. -func (g Gcp) SetValue(key string, value string) (string, error) { - // Create the request to create the secret. - parent := fmt.Sprintf("projects/%s", g.projectID) - createSecretReq := g.newCreateSecretReq(key, parent) - old_value := "" + old_value := []byte{} _, err := g.client.CreateSecret(g.clientctx, &createSecretReq) if err != nil { if !strings.Contains(err.Error(), "code = AlreadyExists") { log.Printf("[ERROR] Failed to create secret: %v\n", err) - return "", err + return []byte{}, err } else { tmp, err := g.GetValue(key) if err != nil { log.Printf("[ERROR] Failed to get old secret: %v\n", err) - return "", err + return []byte{}, err } old_value = tmp } @@ -122,11 +116,10 @@ func (g Gcp) SetValue(key string, value string) (string, error) { } // Call the API. - version, err := g.client.AddSecretVersion(g.clientctx, addSecretVersionReq) + _, err = g.client.AddSecretVersion(g.clientctx, addSecretVersionReq) if err != nil { log.Fatalf("failed to add secret version: %v", err) } - log.Printf("version: %v\n", version) return old_value, nil } @@ -140,11 +133,11 @@ func NewGcp(projectID string) (SecretsManager, error) { tmp, err := GetCurrentGcpProject(ctx) projectID = tmp if err != nil { - fmt.Printf("[ERROR] Failed to get current project ID: %v\n", err) + log.Printf("[ERROR] Failed to get current project ID: %v\n", err) return nil, err } } - fmt.Printf("[DEBUG] Using projectID: %s\n", projectID) + log.Printf("[DEBUG] Using projectID: %s\n", projectID) // Create the client. client, err := secretmanager.NewClient(ctx) diff --git a/tavern/internal/secrets/gcp_test.go b/tavern/internal/secrets/gcp_test.go index 616131e69..a2f7080cd 100644 --- a/tavern/internal/secrets/gcp_test.go +++ b/tavern/internal/secrets/gcp_test.go @@ -18,20 +18,20 @@ package secrets_test // // Get a non existent value // res, err := secretsManager.GetValue(test_key) // assert.NotNil(t, err) -// assert.Equal(t, "", res) +// assert.Equal(t, []byte(""), res) // // Create a value -// res, err = secretsManager.SetValue(test_key, "This should work") +// res, err = secretsManager.SetValue(test_key, []byte("This should work")) // assert.Nil(t, err) -// assert.Equal(t, "", res) +// assert.Equal(t, []byte(""), res) // // Update the value -// res, err = secretsManager.SetValue(test_key, "This should work too") +// res, err = secretsManager.SetValue(test_key, []byte{0x99, 0x99}) // assert.Nil(t, err) -// assert.Equal(t, "This should work", res) +// assert.Equal(t, []byte("This should work"), res) // // Get the value // res, err = secretsManager.GetValue(test_key) // assert.Nil(t, err) -// assert.Equal(t, "This should work too", res) +// assert.Equal(t, []byte{0x99, 0x99}, res) // } diff --git a/tavern/internal/secrets/secrets.go b/tavern/internal/secrets/secrets.go index 99c765aed..0cfb8c22d 100644 --- a/tavern/internal/secrets/secrets.go +++ b/tavern/internal/secrets/secrets.go @@ -2,6 +2,6 @@ package secrets type SecretsManager interface { GetName() string - SetValue(string, string) (string, error) - GetValue(string) (string, error) + SetValue(string, []byte) ([]byte, error) + GetValue(string) ([]byte, error) } From 054eba490a7f2b92e368b0fa0dc59b264e1a6289 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Sun, 7 Jul 2024 21:48:04 +0000 Subject: [PATCH 046/141] key stays the same between reboots. --- tavern/app.go | 15 ++++++++++----- tavern/internal/secrets/debug_file.go | 3 --- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/tavern/app.go b/tavern/app.go index 0523230fa..3eae69ddb 100644 --- a/tavern/app.go +++ b/tavern/app.go @@ -328,8 +328,8 @@ func generate_key_pair() (*ecdh.PublicKey, *ecdh.PrivateKey) { func getKeyPair() (*ecdh.PublicKey, *ecdh.PrivateKey) { x22519 := ecdh.X25519() - // secretsManager, err := secrets.NewGcp("") - secretsManager, err := secrets.NewDebugFileSecrets("/etc/realm-secrets.txt") + secretsManager, err := secrets.NewGcp("") + // secretsManager, err := secrets.NewDebugFileSecrets("/etc/realm-secrets.txt") if err != nil { log.Printf("[ERROR] Unable to setup secrets manager\n") } @@ -338,13 +338,18 @@ func getKeyPair() (*ecdh.PublicKey, *ecdh.PrivateKey) { priv_key_string, err := secretsManager.GetValue("tavern_encryption_private_key") if err != nil { // Generate a new one if it doesn't exist - priv_key, pub_key := generate_key_pair() - _, err = secretsManager.SetValue("tavern_encryption_private_key", priv_key.Bytes()) + pub_key, priv_key := generate_key_pair() + priv_key_bytes, err := x509.MarshalPKCS8PrivateKey(priv_key) + if err != nil { + log.Printf("[ERROR] Unable to set marshal priv key: %v", err) + return nil, nil + } + _, err = secretsManager.SetValue("tavern_encryption_private_key", priv_key_bytes) if err != nil { log.Printf("[ERROR] Unable to set 'tavern_encryption_private_key' using secrets manager: %v", err) return nil, nil } - return priv_key, pub_key + return pub_key, priv_key } // Parse private key bytes diff --git a/tavern/internal/secrets/debug_file.go b/tavern/internal/secrets/debug_file.go index 68bc7da92..a988eee3d 100644 --- a/tavern/internal/secrets/debug_file.go +++ b/tavern/internal/secrets/debug_file.go @@ -54,7 +54,6 @@ func (s DebugFileSecrets) SetValue(key string, value []byte) ([]byte, error) { var old_value []byte = []byte{} - log.Printf("[ERROR] Before: %v\n", secrets.Secrets) // If the value exists update it for idx, k := range secrets.Secrets { if k.Key == key { @@ -73,7 +72,6 @@ func (s DebugFileSecrets) SetValue(key string, value []byte) ([]byte, error) { }, ) } - log.Printf("[ERROR] After: %v\n", secrets.Secrets) err = s.setYamlStruct(path, secrets) if err != nil { @@ -94,7 +92,6 @@ func (s DebugFileSecrets) GetValue(key string) ([]byte, error) { } for _, k := range secrets.Secrets { - fmt.Printf("key: %s\n", k) if k.Key == key { return []byte(k.Value), nil } From 7f3495b507c617a8950620d4d018f0355d95a896 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Sun, 7 Jul 2024 23:41:35 +0000 Subject: [PATCH 047/141] Add prefix --- tavern/internal/secrets/gcp.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tavern/internal/secrets/gcp.go b/tavern/internal/secrets/gcp.go index 62bbf006c..c79c27b6a 100644 --- a/tavern/internal/secrets/gcp.go +++ b/tavern/internal/secrets/gcp.go @@ -17,6 +17,7 @@ import ( type Gcp struct { Name string projectID string + prefix string client *secretmanager.Client clientctx context.Context } @@ -29,7 +30,7 @@ func (g Gcp) GetName() string { // GetValue implements SecretsManager. func (g Gcp) GetValue(key string) ([]byte, error) { // name := "projects/my-project/secrets/my-secret" - name := fmt.Sprintf("projects/%s/secrets/%s/versions/latest", g.projectID, key) + name := fmt.Sprintf("projects/%s/secrets/%s_%s/versions/latest", g.projectID, g.prefix, key) // Build the request. accessRequest := &secretmanagerpb.AccessSecretVersionRequest{ @@ -77,7 +78,7 @@ func (g Gcp) SetValue(key string, value []byte) ([]byte, error) { parent := fmt.Sprintf("projects/%s", g.projectID) createSecretReq := secretmanagerpb.CreateSecretRequest{ Parent: parent, - SecretId: key, + SecretId: fmt.Sprintf("%s_%s", g.prefix, key), Secret: &secretmanagerpb.Secret{ Replication: &secretmanagerpb.Replication{ Replication: &secretmanagerpb.Replication_Automatic_{ @@ -104,7 +105,7 @@ func (g Gcp) SetValue(key string, value []byte) ([]byte, error) { } // Declare the payload to store. - path := fmt.Sprintf("%s/secrets/%s", parent, key) + path := fmt.Sprintf("%s/secrets/%s_%s", parent, g.prefix, key) payload := []byte(value) // Build the request. @@ -149,6 +150,7 @@ func NewGcp(projectID string) (SecretsManager, error) { return Gcp{ Name: "Gcp", projectID: projectID, + prefix: "REALM", client: client, clientctx: ctx, }, nil From 4094ef19b7c27d99b9a20497ed6f91681dee1bbf Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 8 Jul 2024 23:20:13 -0400 Subject: [PATCH 048/141] Debugging --- tavern/internal/secrets/gcp.go | 1 + terraform/main.tf | 44 ++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/tavern/internal/secrets/gcp.go b/tavern/internal/secrets/gcp.go index 62bbf006c..b08ef19c7 100644 --- a/tavern/internal/secrets/gcp.go +++ b/tavern/internal/secrets/gcp.go @@ -52,6 +52,7 @@ type credentialsJson struct { func GetCurrentGcpProject(ctx context.Context) (string, error) { respMesg, err := google.FindDefaultCredentials(ctx, compute.ComputeScope) + log.Printf("[DEBUG] Default creds: %v\n", respMesg) if err != nil { return "", err } diff --git a/terraform/main.tf b/terraform/main.tf index 0ee9cfa21..f5155c114 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -31,6 +31,11 @@ variable "gcp_project" { error_message = "Must provide a valid gcp_project" } } + +data "google_project" "project" { + project_id = var.gcp_project +} + variable "gcp_region" { type = string description = "GCP Region for deployment" @@ -104,6 +109,11 @@ resource "google_project_service" "cloud_run_api" { disable_on_destroy = false } +resource "google_project_service" "secret_manager" { + service = "secretmanager.googleapis.com" + disable_on_destroy = false +} + resource "google_project_service" "cloud_sqladmin_api" { service = "sqladmin.googleapis.com" disable_on_destroy = false @@ -146,6 +156,36 @@ locals { prometheus_container_name = "prometheus-sidecar" } +resource "google_service_account" "svctavern" { + account_id = "svctavern" + description = "The service account Realm's Tavern uses to connect to GCP based services. Managed by Terraform." +} + +resource "google_secret_manager_secret" "tavern-grpc-priv-key" { + secret_id = "tavern_encryption_private_key" + + replication { + auto { + } + } +} + +resource "google_secret_manager_secret_iam_binding" "tavern-secrets-binding" { + project = var.gcp_project + secret_id = google_secret_manager_secret.tavern-grpc-priv-key.secret_id + role = "roles/secretmanager.secretAccessor" + members = [ + "serviceAccount:${google_service_account.svctavern.email}", + ] +} + +resource "google_project_iam_member" "tavern-sqlclient-binding" { + project = var.gcp_project + role = "roles/cloudsql.client" + member = "serviceAccount:${google_service_account.svctavern.email}" +} + + resource "google_cloud_run_service" "tavern" { name = "tavern" location = var.gcp_region @@ -157,6 +197,8 @@ resource "google_cloud_run_service" "tavern" { template { spec { + service_account_name = google_service_account.svctavern.email + containers { name = local.tavern_container_name image = var.tavern_container_image @@ -230,6 +272,8 @@ resource "google_cloud_run_service" "tavern" { autogenerate_revision_name = true depends_on = [ + google_project_iam_member.tavern-sqlclient-binding, + google_secret_manager_secret_iam_binding.tavern-secrets-binding, google_project_service.cloud_run_api, google_project_service.cloud_sqladmin_api, google_sql_user.tavern-user, From 967cb508244bf6d68666455f3abcfeb7e97f1017 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 8 Jul 2024 23:25:34 -0400 Subject: [PATCH 049/141] Check another way --- tavern/internal/secrets/gcp.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tavern/internal/secrets/gcp.go b/tavern/internal/secrets/gcp.go index 474f8fe6a..a0ef86907 100644 --- a/tavern/internal/secrets/gcp.go +++ b/tavern/internal/secrets/gcp.go @@ -53,11 +53,14 @@ type credentialsJson struct { func GetCurrentGcpProject(ctx context.Context) (string, error) { respMesg, err := google.FindDefaultCredentials(ctx, compute.ComputeScope) - log.Printf("[DEBUG] Default creds: %v\n", respMesg) if err != nil { return "", err } + if respMesg.ProjectID != "" { + return respMesg.ProjectID, nil + } + // respMesg.ProjectID can be empty so instead we grab from the creds JSON file credJSON := credentialsJson{} err = json.Unmarshal(respMesg.JSON, &credJSON) From 3897e0aac6afdebbbebc86efe13e695c5679466a Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 8 Jul 2024 23:28:38 -0400 Subject: [PATCH 050/141] Fix secret name --- terraform/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terraform/main.tf b/terraform/main.tf index f5155c114..80ff67c54 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -162,7 +162,7 @@ resource "google_service_account" "svctavern" { } resource "google_secret_manager_secret" "tavern-grpc-priv-key" { - secret_id = "tavern_encryption_private_key" + secret_id = "REALM_tavern_encryption_private_key" replication { auto { From c0d4d5b06915067b87c643505bdd144afaae0a0a Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 9 Jul 2024 21:04:47 +0000 Subject: [PATCH 051/141] Don't try to create secrets --- tavern/internal/secrets/gcp.go | 50 ++++++++++++++++------------------ 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/tavern/internal/secrets/gcp.go b/tavern/internal/secrets/gcp.go index a0ef86907..9f2934e7d 100644 --- a/tavern/internal/secrets/gcp.go +++ b/tavern/internal/secrets/gcp.go @@ -80,32 +80,30 @@ func GetCurrentGcpProject(ctx context.Context) (string, error) { func (g Gcp) SetValue(key string, value []byte) ([]byte, error) { // Create the request to create the secret. parent := fmt.Sprintf("projects/%s", g.projectID) - createSecretReq := secretmanagerpb.CreateSecretRequest{ - Parent: parent, - SecretId: fmt.Sprintf("%s_%s", g.prefix, key), - Secret: &secretmanagerpb.Secret{ - Replication: &secretmanagerpb.Replication{ - Replication: &secretmanagerpb.Replication_Automatic_{ - Automatic: &secretmanagerpb.Replication_Automatic{}, - }, - }, - }, - } - - old_value := []byte{} - _, err := g.client.CreateSecret(g.clientctx, &createSecretReq) - if err != nil { - if !strings.Contains(err.Error(), "code = AlreadyExists") { - log.Printf("[ERROR] Failed to create secret: %v\n", err) - return []byte{}, err - } else { - tmp, err := g.GetValue(key) - if err != nil { - log.Printf("[ERROR] Failed to get old secret: %v\n", err) - return []byte{}, err - } - old_value = tmp - } + // createSecretReq := secretmanagerpb.CreateSecretRequest{ + // Parent: parent, + // SecretId: fmt.Sprintf("%s_%s", g.prefix, key), + // Secret: &secretmanagerpb.Secret{ + // Replication: &secretmanagerpb.Replication{ + // Replication: &secretmanagerpb.Replication_Automatic_{ + // Automatic: &secretmanagerpb.Replication_Automatic{}, + // }, + // }, + // }, + // } + + // _, err := g.client.CreateSecret(g.clientctx, &createSecretReq) + // if err != nil { + // if !strings.Contains(err.Error(), "code = AlreadyExists") { + // log.Printf("[ERROR] Failed to create secret: %v\n", err) + // return []byte{}, err + // } else { + // } + + old_value, err := g.GetValue(key) + if err != nil && !strings.Contains(err.Error(), "code = NotFound") { + log.Printf("[ERROR] Failed to get old secret: %v\n", err) + return []byte{}, err } // Declare the payload to store. From e81dc7db9e73e98ec97b5094f4c9e7d8f2636d43 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 9 Jul 2024 17:39:35 -0400 Subject: [PATCH 052/141] And the peasants rejoice --- tavern/internal/secrets/gcp.go | 2 +- terraform/main.tf | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/tavern/internal/secrets/gcp.go b/tavern/internal/secrets/gcp.go index 9f2934e7d..a9237210d 100644 --- a/tavern/internal/secrets/gcp.go +++ b/tavern/internal/secrets/gcp.go @@ -98,7 +98,7 @@ func (g Gcp) SetValue(key string, value []byte) ([]byte, error) { // log.Printf("[ERROR] Failed to create secret: %v\n", err) // return []byte{}, err // } else { - // } + // }h old_value, err := g.GetValue(key) if err != nil && !strings.Contains(err.Error(), "code = NotFound") { diff --git a/terraform/main.tf b/terraform/main.tf index 80ff67c54..e672a432f 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -185,6 +185,18 @@ resource "google_project_iam_member" "tavern-sqlclient-binding" { member = "serviceAccount:${google_service_account.svctavern.email}" } +resource "google_project_iam_member" "tavern-metricwriter-binding" { + project = var.gcp_project + role = "roles/monitoring.metricWriter" + member = "serviceAccount:${google_service_account.svctavern.email}" +} + +resource "google_project_iam_member" "tavern-logwriter-binding" { + project = var.gcp_project + role = "roles/logging.logWriter" + member = "serviceAccount:${google_service_account.svctavern.email}" +} + resource "google_cloud_run_service" "tavern" { name = "tavern" @@ -274,6 +286,8 @@ resource "google_cloud_run_service" "tavern" { depends_on = [ google_project_iam_member.tavern-sqlclient-binding, google_secret_manager_secret_iam_binding.tavern-secrets-binding, + google_project_iam_member.tavern-metricwriter-binding, + google_project_iam_member.tavern-logwriter-binding, google_project_service.cloud_run_api, google_project_service.cloud_sqladmin_api, google_sql_user.tavern-user, From 91088b7235d739ddea6da7fb9bb300fe8e8915f3 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 9 Jul 2024 21:48:05 +0000 Subject: [PATCH 053/141] Remove create secret code --- tavern/internal/secrets/gcp.go | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/tavern/internal/secrets/gcp.go b/tavern/internal/secrets/gcp.go index a9237210d..f9b894cb2 100644 --- a/tavern/internal/secrets/gcp.go +++ b/tavern/internal/secrets/gcp.go @@ -80,25 +80,6 @@ func GetCurrentGcpProject(ctx context.Context) (string, error) { func (g Gcp) SetValue(key string, value []byte) ([]byte, error) { // Create the request to create the secret. parent := fmt.Sprintf("projects/%s", g.projectID) - // createSecretReq := secretmanagerpb.CreateSecretRequest{ - // Parent: parent, - // SecretId: fmt.Sprintf("%s_%s", g.prefix, key), - // Secret: &secretmanagerpb.Secret{ - // Replication: &secretmanagerpb.Replication{ - // Replication: &secretmanagerpb.Replication_Automatic_{ - // Automatic: &secretmanagerpb.Replication_Automatic{}, - // }, - // }, - // }, - // } - - // _, err := g.client.CreateSecret(g.clientctx, &createSecretReq) - // if err != nil { - // if !strings.Contains(err.Error(), "code = AlreadyExists") { - // log.Printf("[ERROR] Failed to create secret: %v\n", err) - // return []byte{}, err - // } else { - // }h old_value, err := g.GetValue(key) if err != nil && !strings.Contains(err.Error(), "code = NotFound") { From db4601ab64e2039de1c958542876d98ca07a42e2 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 9 Jul 2024 21:56:58 +0000 Subject: [PATCH 054/141] Remove debug print --- tavern/internal/cryptocodec/cryptocodec.go | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/tavern/internal/cryptocodec/cryptocodec.go b/tavern/internal/cryptocodec/cryptocodec.go index d09fb21db..ae97f4197 100644 --- a/tavern/internal/cryptocodec/cryptocodec.go +++ b/tavern/internal/cryptocodec/cryptocodec.go @@ -5,7 +5,6 @@ import ( "crypto/ecdh" "crypto/rand" "errors" - "fmt" "log" "runtime" "strconv" @@ -96,17 +95,16 @@ func (csvc *CryptoSvc) SetAgentPubkey(client_pub_key []byte) { } func (csvc *CryptoSvc) generate_shared_key(client_pub_key_bytes []byte) []byte { - fmt.Println("[DEBUG] client_pub_key_bytes: ", client_pub_key_bytes) x22519_curve := ecdh.X25519() client_pub_key, err := x22519_curve.NewPublicKey(client_pub_key_bytes) if err != nil { - log.Printf("[ERROR] Failed to create public key %v", err) + log.Printf("[ERROR] Failed to create public key %v\n", err) return FAILURE_BYTES } shared_key, err := csvc.priv_key.ECDH(client_pub_key) if err != nil { - log.Printf("[ERROR] Failed to get shared secret %v", err) + log.Printf("[ERROR] Failed to get shared secret %v\n", err) return FAILURE_BYTES } @@ -116,7 +114,7 @@ func (csvc *CryptoSvc) generate_shared_key(client_pub_key_bytes []byte) []byte { func (csvc *CryptoSvc) Decrypt(in_arr []byte) ([]byte, []byte) { // Read in pub key if len(in_arr) < x25519.Size { - fmt.Printf("Input bytes to short %d expected at least %d\n", len(in_arr), x25519.Size) + log.Printf("[ERROR] Input bytes to short %d expected at least %d\n", len(in_arr), x25519.Size) return FAILURE_BYTES, FAILURE_BYTES } @@ -126,10 +124,9 @@ func (csvc *CryptoSvc) Decrypt(in_arr []byte) ([]byte, []byte) { // Generate shared secret derived_key := csvc.generate_shared_key(client_pub_key_bytes) - log.Println("[DEBUG] derived_key: ", derived_key) aead, err := chacha20poly1305.NewX(derived_key) if err != nil { - log.Printf("[ERROR] Failed to create xchacha key %v", err) + log.Printf("[ERROR] Failed to create xchacha key %v\n", err) return FAILURE_BYTES, FAILURE_BYTES } @@ -138,7 +135,7 @@ func (csvc *CryptoSvc) Decrypt(in_arr []byte) ([]byte, []byte) { // Read nonce if len(in_arr) < aead.NonceSize() { - fmt.Printf("Input bytes to short %d expected at least %d\n", len(in_arr), aead.NonceSize()) + log.Printf("[ERROR] Input bytes to short %d expected at least %d\n", len(in_arr), aead.NonceSize()) return FAILURE_BYTES, FAILURE_BYTES } nonce, ciphertext := in_arr[:aead.NonceSize()], in_arr[aead.NonceSize():] @@ -146,7 +143,7 @@ func (csvc *CryptoSvc) Decrypt(in_arr []byte) ([]byte, []byte) { // Decrypt plaintext, err := aead.Open(nil, nonce, ciphertext, nil) if err != nil { - fmt.Printf("Failed to decrypt %v\n", err) + log.Printf("[ERROR] Failed to decrypt %v\n", err) return FAILURE_BYTES, FAILURE_BYTES } @@ -157,19 +154,18 @@ func (csvc *CryptoSvc) Decrypt(in_arr []byte) ([]byte, []byte) { func (csvc *CryptoSvc) Encrypt(in_arr []byte) []byte { // Get the client pub key? client_pub_key_bytes := csvc.GetAgentPubkey() - fmt.Println("[DEBUG] Got pub key: ", client_pub_key_bytes) // Generate shared secret shared_key := csvc.generate_shared_key(client_pub_key_bytes) aead, err := chacha20poly1305.NewX(shared_key) if err != nil { - log.Printf("[ERROR] Failed to create xchacha key %v", err) + log.Printf("[ERROR] Failed to create xchacha key %v\n", err) return FAILURE_BYTES } nonce := make([]byte, aead.NonceSize(), aead.NonceSize()+len(in_arr)+aead.Overhead()) if _, err := rand.Read(nonce); err != nil { - fmt.Printf("Failed to encrypt %v\n", err) + log.Printf("[ERROR] Failed to encrypt %v\n", err) return FAILURE_BYTES } encryptedMsg := aead.Seal(nonce, nonce, in_arr, nil) From de4c8e69ac56d74a5a8c9318b5ae2e5cf3ae23de Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 9 Jul 2024 22:09:20 +0000 Subject: [PATCH 055/141] Fix tests --- tavern/internal/secrets/debug_file_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tavern/internal/secrets/debug_file_test.go b/tavern/internal/secrets/debug_file_test.go index 10b6a81b8..167f12eb9 100644 --- a/tavern/internal/secrets/debug_file_test.go +++ b/tavern/internal/secrets/debug_file_test.go @@ -19,7 +19,7 @@ secrets: - key: TAVERN_PRIVATE_KEY value: !!binary Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE= - key: super_secret_test_data - value: !!binary NjggNjUgNmMgNmMgNmYgMjAgNzcgNmYgNzIgNmMgNjQgMjE= + value: hello world! `) err := os.WriteFile(secretsPath, data, 0644) if err != nil { @@ -41,7 +41,7 @@ func TestGetSecretsFile(t *testing.T) { res, err = secretsManager.GetValue("TAVERN_PRIVATE_KEY") assert.Nil(t, err) - assert.Equal(t, []byte("Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE="), res) + assert.Equal(t, []byte{0x15, 0xef, 0x04, 0xfd, 0x25, 0x5f, 0xec, 0xc2, 0xe0, 0x08, 0x7c, 0xc1, 0x5a, 0xf8, 0xdd, 0x9d, 0xab, 0xde, 0x8e, 0xc2, 0x62, 0x8c, 0x96, 0x43, 0xf6, 0x63, 0xef, 0x2d, 0x06, 0xe0, 0xc9, 0xb1}, res) } func TestSetSecretsAddFile(t *testing.T) { @@ -72,7 +72,7 @@ func TestSetSecretsAddFile(t *testing.T) { res, err = secretsManager.GetValue("TAVERN_PRIVATE_KEY") assert.Nil(t, err) - assert.Equal(t, []byte("Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE="), res) + assert.Equal(t, []byte{0x15, 0xef, 0x04, 0xfd, 0x25, 0x5f, 0xec, 0xc2, 0xe0, 0x08, 0x7c, 0xc1, 0x5a, 0xf8, 0xdd, 0x9d, 0xab, 0xde, 0x8e, 0xc2, 0x62, 0x8c, 0x96, 0x43, 0xf6, 0x63, 0xef, 0x2d, 0x06, 0xe0, 0xc9, 0xb1}, res) } func TestSetSecretsNewFile(t *testing.T) { From 8e53f574faf4f37e7bbdefed2dafb70c9571b6f6 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 9 Jul 2024 22:22:50 +0000 Subject: [PATCH 056/141] Secrets manager defaults --- tavern/app.go | 25 ++++++++++++++++++------- tavern/config.go | 3 +++ tavern/main_test.go | 1 + 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/tavern/app.go b/tavern/app.go index 3eae69ddb..93cb1e5d1 100644 --- a/tavern/app.go +++ b/tavern/app.go @@ -309,27 +309,33 @@ func newGraphQLHandler(client *ent.Client, repoImporter graphql.RepoImporter) ht }) } -func generate_key_pair() (*ecdh.PublicKey, *ecdh.PrivateKey) { +func generate_key_pair() (*ecdh.PublicKey, *ecdh.PrivateKey, error) { x22519 := ecdh.X25519() priv_key, err := x22519.GenerateKey(rand.Reader) if err != nil { log.Printf("[ERROR] Failed to generate private key: %v\n", err) - panic("[ERROR] Failed to generate private key") + return nil, nil, err } public_key, err := x22519.NewPublicKey(priv_key.PublicKey().Bytes()) if err != nil { log.Printf("[ERROR] Failed to generate public key: %v\n", err) - panic("[ERROR] Failed to generate public key") + return nil, nil, err } - return public_key, priv_key + return public_key, priv_key, nil } func getKeyPair() (*ecdh.PublicKey, *ecdh.PrivateKey) { x22519 := ecdh.X25519() - secretsManager, err := secrets.NewGcp("") - // secretsManager, err := secrets.NewDebugFileSecrets("/etc/realm-secrets.txt") + var secretsManager secrets.SecretsManager + var err error + + if EnvSecretsManagerPath.String() == "" { + secretsManager, err = secrets.NewGcp("") + } else { + secretsManager, err = secrets.NewDebugFileSecrets(EnvSecretsManagerPath.String()) + } if err != nil { log.Printf("[ERROR] Unable to setup secrets manager\n") } @@ -338,7 +344,12 @@ func getKeyPair() (*ecdh.PublicKey, *ecdh.PrivateKey) { priv_key_string, err := secretsManager.GetValue("tavern_encryption_private_key") if err != nil { // Generate a new one if it doesn't exist - pub_key, priv_key := generate_key_pair() + pub_key, priv_key, err := generate_key_pair() + if err != nil { + log.Printf("[ERROR] Key generation failed: %v", err) + return nil, nil + } + priv_key_bytes, err := x509.MarshalPKCS8PrivateKey(priv_key) if err != nil { log.Printf("[ERROR] Unable to set marshal priv key: %v", err) diff --git a/tavern/config.go b/tavern/config.go index 54531df05..890012286 100644 --- a/tavern/config.go +++ b/tavern/config.go @@ -71,6 +71,9 @@ var ( // EnvEnableMetrics enables the /metrics endpoint and HTTP server. It is unauthenticated and should be used carefully. EnvEnablePProf = EnvString{"ENABLE_PPROF", ""} EnvEnableMetrics = EnvString{"ENABLE_METRICS", ""} + + // EnvSecretsManagerPath defines the local path on disk where secrets should be stored by the DebugFile secrets manager. If left empty uses GCP + EnvSecretsManagerPath = EnvString{"SECRETS_FILE_PATH", ""} ) // Config holds information that controls the behaviour of Tavern diff --git a/tavern/main_test.go b/tavern/main_test.go index c72d524f8..48517e870 100644 --- a/tavern/main_test.go +++ b/tavern/main_test.go @@ -13,6 +13,7 @@ func TestMainFunc(t *testing.T) { os.Setenv(EnvHTTPMetricsListenAddr.Key, "127.0.0.1:8081") os.Setenv(EnvEnablePProf.Key, "1") os.Setenv(EnvEnableMetrics.Key, "1") + os.Setenv(EnvSecretsManagerPath.Key, "/tmp/test-secret.yml") defer func() { unsetList := []string{ EnvEnableTestRunAndExit.Key, From 9c95a6e90fabb3f247129d5826ce6ce7e98af10d Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 9 Jul 2024 23:01:54 +0000 Subject: [PATCH 057/141] Add env var to tests --- .github/workflows/tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3b65662bf..41535c725 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -9,7 +9,6 @@ on: env: CARGO_TERM_COLOR: always - SERVER_PUBKEY: "pR56vDJZb9b3BL3ZvCXIvgK0r2vCk7FiZ1RjeEhJVyU=" jobs: tavern: @@ -36,6 +35,8 @@ jobs: implants: runs-on: ${{ matrix.os }} timeout-minutes: 60 + env: + SERVER_PUBKEY: "pR56vDJZb9b3BL3ZvCXIvgK0r2vCk7FiZ1RjeEhJVyU=" strategy: matrix: os: From dff90f3eebb2b3f4ef0870cc7a6e18acd8651884 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 9 Jul 2024 23:14:31 +0000 Subject: [PATCH 058/141] typo --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 41535c725..a848b6366 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -36,7 +36,7 @@ jobs: runs-on: ${{ matrix.os }} timeout-minutes: 60 env: - SERVER_PUBKEY: "pR56vDJZb9b3BL3ZvCXIvgK0r2vCk7FiZ1RjeEhJVyU=" + IMIX_SERVER_PUBKEY: "pR56vDJZb9b3BL3ZvCXIvgK0r2vCk7FiZ1RjeEhJVyU=" strategy: matrix: os: From ea1f6547b764633806833f2afd382dccce3578a1 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 9 Jul 2024 23:15:43 +0000 Subject: [PATCH 059/141] Let test cleanup temp files --- tavern/internal/secrets/debug_file_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tavern/internal/secrets/debug_file_test.go b/tavern/internal/secrets/debug_file_test.go index 167f12eb9..92a6ff674 100644 --- a/tavern/internal/secrets/debug_file_test.go +++ b/tavern/internal/secrets/debug_file_test.go @@ -31,7 +31,6 @@ secrets: func TestGetSecretsFile(t *testing.T) { path := createTestSecrets(t) - defer os.Remove(path) secretsManager, err := secrets.NewDebugFileSecrets(path) assert.Nil(t, err) @@ -46,7 +45,6 @@ func TestGetSecretsFile(t *testing.T) { func TestSetSecretsAddFile(t *testing.T) { path := createTestSecrets(t) - defer os.Remove(path) secretsManager, err := secrets.NewDebugFileSecrets(path) assert.Nil(t, err) @@ -78,8 +76,6 @@ func TestSetSecretsAddFile(t *testing.T) { func TestSetSecretsNewFile(t *testing.T) { tmpDir := t.TempDir() path := path.Join(tmpDir, "secrets.yaml") - defer os.Remove(path) - // path = "/tmp/test-secrets.yaml" secretsManager, err := secrets.NewDebugFileSecrets(path) assert.Nil(t, err) From 4a0afe421fe2161d267f5229fa0a74cb6f129acc Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 9 Jul 2024 23:34:42 +0000 Subject: [PATCH 060/141] defer close --- tavern/internal/secrets/debug_file.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tavern/internal/secrets/debug_file.go b/tavern/internal/secrets/debug_file.go index a988eee3d..076c84040 100644 --- a/tavern/internal/secrets/debug_file.go +++ b/tavern/internal/secrets/debug_file.go @@ -112,6 +112,7 @@ func (s DebugFileSecrets) setYamlStruct(path string, secrets Secrets) error { log.Printf("[ERROR] Failed to open secrets file %s: %v", path, err) return err } + defer file.Close() _, err = file.Write(data) if err != nil { @@ -128,6 +129,7 @@ func (s DebugFileSecrets) getYamlStruct(path string) (Secrets, error) { log.Printf("[ERROR] Failed to open secrets file %s: %v", path, err) return Secrets{}, err } + defer file.Close() data := make([]byte, MAX_FILE_SIZE) n, err := file.Read(data) @@ -168,9 +170,3 @@ func (s DebugFileSecrets) ensureSecretsFileExist() (string, error) { } return s.Path, nil } - -// func checkFileExists(filePath string) bool { -// _, error := os.Stat(filePath) -// //return !os.IsNotExist(err) -// return !errors.Is(error, os.ErrNotExist) -// } From 8c5487f2807742717d5876611e40c4dbee247364 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 9 Jul 2024 23:47:35 +0000 Subject: [PATCH 061/141] Test using tempdir --- tavern/main_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tavern/main_test.go b/tavern/main_test.go index 48517e870..809ae7ffc 100644 --- a/tavern/main_test.go +++ b/tavern/main_test.go @@ -2,18 +2,22 @@ package main import ( "os" + "path" "testing" ) // TestMainFunc runs main after configuring the application to immediately exit. // This validates our default configurations are successful. func TestMainFunc(t *testing.T) { + tmpDir := t.TempDir() + path := path.Join(tmpDir, "secrets.yaml") + os.Setenv(EnvEnableTestRunAndExit.Key, "1") os.Setenv(EnvHTTPListenAddr.Key, "127.0.0.1:8080") os.Setenv(EnvHTTPMetricsListenAddr.Key, "127.0.0.1:8081") os.Setenv(EnvEnablePProf.Key, "1") os.Setenv(EnvEnableMetrics.Key, "1") - os.Setenv(EnvSecretsManagerPath.Key, "/tmp/test-secret.yml") + os.Setenv(EnvSecretsManagerPath.Key, path) defer func() { unsetList := []string{ EnvEnableTestRunAndExit.Key, From 650b169b4c1c1b014d96cfc1ff5701d02bcb812e Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 10 Jul 2024 00:53:54 +0000 Subject: [PATCH 062/141] Resolve feedback --- docs/_docs/user-guide/imix.md | 10 ++++++---- implants/lib/pb/src/generated/c2.rs | 1 - implants/lib/pb/src/generated/eldritch.rs | 1 - tavern/app.go | 2 +- tavern/internal/secrets/gcp.go | 3 +-- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/docs/_docs/user-guide/imix.md b/docs/_docs/user-guide/imix.md index c3b913b89..3f32e79b7 100644 --- a/docs/_docs/user-guide/imix.md +++ b/docs/_docs/user-guide/imix.md @@ -77,6 +77,8 @@ This isn't ideal as in the UI each new beacon will appear as thought it were on **We strongly recommend building agents inside the provided devcontainer `.devcontainer`** Building in the dev container limits variables that might cause issues and is the most tested way to compile. +**Imix requires a server public key so it can encrypt messsages to and from the server check the server log for `[INFO] Public key: `** + ### Linux ```bash @@ -86,7 +88,7 @@ sudo apt update sudo apt install musl-tools cd realm/implants/imix/ -RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --target=x86_64-unknown-linux-musl +IMIX_SERVER_PUBKEY="" RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --target=x86_64-unknown-linux-musl ``` ### MacOS @@ -110,9 +112,9 @@ sudo apt install gcc-mingw-w64 cd realm/implants/imix/ # Build imix.exe -RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --target=x86_64-pc-windows-gnu +IMIX_SERVER_PUBKEY="" RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --target=x86_64-pc-windows-gnu # Build imix.svc.exe -RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --features win_service --target=x86_64-pc-windows-gnu +IMIX_SERVER_PUBKEY="" RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --features win_service --target=x86_64-pc-windows-gnu # Build imix.dll -RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --lib --target=x86_64-pc-windows-gnu +IMIX_SERVER_PUBKEY="" RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --lib --target=x86_64-pc-windows-gnu ``` diff --git a/implants/lib/pb/src/generated/c2.rs b/implants/lib/pb/src/generated/c2.rs index f1f0ec87e..459967e74 100644 --- a/implants/lib/pb/src/generated/c2.rs +++ b/implants/lib/pb/src/generated/c2.rs @@ -1,4 +1,3 @@ -// This file is @generated by prost-build. /// Agent information to identify the type of beacon. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/implants/lib/pb/src/generated/eldritch.rs b/implants/lib/pb/src/generated/eldritch.rs index ac4647c34..6c7cac2b2 100644 --- a/implants/lib/pb/src/generated/eldritch.rs +++ b/implants/lib/pb/src/generated/eldritch.rs @@ -1,4 +1,3 @@ -// This file is @generated by prost-build. /// Tome for eldritch to execute. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/tavern/app.go b/tavern/app.go index 9efa86933..3e0b28539 100644 --- a/tavern/app.go +++ b/tavern/app.go @@ -355,7 +355,7 @@ func getKeyPair() (*ecdh.PublicKey, *ecdh.PrivateKey) { priv_key_bytes, err := x509.MarshalPKCS8PrivateKey(priv_key) if err != nil { - log.Printf("[ERROR] Unable to set marshal priv key: %v", err) + log.Printf("[ERROR] Unable to marshal private key: %v", err) return nil, nil } _, err = secretsManager.SetValue("tavern_encryption_private_key", priv_key_bytes) diff --git a/tavern/internal/secrets/gcp.go b/tavern/internal/secrets/gcp.go index f9b894cb2..54c05d7a6 100644 --- a/tavern/internal/secrets/gcp.go +++ b/tavern/internal/secrets/gcp.go @@ -29,7 +29,6 @@ func (g Gcp) GetName() string { // GetValue implements SecretsManager. func (g Gcp) GetValue(key string) ([]byte, error) { - // name := "projects/my-project/secrets/my-secret" name := fmt.Sprintf("projects/%s/secrets/%s_%s/versions/latest", g.projectID, g.prefix, key) // Build the request. @@ -109,11 +108,11 @@ func (g Gcp) SetValue(key string, value []byte) ([]byte, error) { } func NewGcp(projectID string) (SecretsManager, error) { - // GCP project in which to store secrets in Secret Manager. ctx := context.Background() // If unset try to figure out the current GCP if projectID == "" { + // GCP project in which to store secrets in Secret Manager. tmp, err := GetCurrentGcpProject(ctx) projectID = tmp if err != nil { From 3db67fa1b61280e59a8ed118ed3b2b4960f38bc6 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Thu, 11 Jul 2024 22:36:47 +0000 Subject: [PATCH 063/141] Cleanup. --- tavern/internal/cryptocodec/cryptocodec.go | 82 +++++++++++++++------- 1 file changed, 55 insertions(+), 27 deletions(-) diff --git a/tavern/internal/cryptocodec/cryptocodec.go b/tavern/internal/cryptocodec/cryptocodec.go index ae97f4197..71607c230 100644 --- a/tavern/internal/cryptocodec/cryptocodec.go +++ b/tavern/internal/cryptocodec/cryptocodec.go @@ -16,9 +16,37 @@ import ( ) // TODO: Switch to a gomap and mutex. -var session_pub_keys = sync.Map{} +var session_pub_keys = NewSyncMap() -// TODO: Should we make this a random long byte array in case it gets used anywhere to avoid encrypting data with a week key? - Sliver handles errors in this way. +type SyncMap struct { + Mutex sync.RWMutex // Read Write Mutex to allow for multiple readers + Map map[int][]byte // Example data map +} + +func NewSyncMap() *SyncMap { + return &SyncMap{Mutex: sync.RWMutex{}, Map: make(map[int][]byte)} +} + +func (s *SyncMap) Load(key int) ([]byte, bool) { + defer s.Mutex.Unlock() + s.Mutex.Lock() + res, ok := s.Map[key] + return res, ok +} + +func (s *SyncMap) Store(key int, value []byte) { + defer s.Mutex.Unlock() + s.Mutex.Lock() + s.Map[key] = value +} + +func (s *SyncMap) Delete(key int) { + defer s.Mutex.Unlock() + s.Mutex.Lock() + delete(s.Map, key) +} + +// TODO: Should we make this a random long byte array in case it gets used anywhere to avoid encrypting data with a weak key? - Sliver handles errors in this way. var FAILURE_BYTES = []byte{} func init() { @@ -53,7 +81,9 @@ func (s StreamDecryptCodec) Unmarshal(buf []byte, v any) error { return err } dec_buf, pub_key := s.Csvc.Decrypt(buf) - s.Csvc.SetAgentPubkey(pub_key) + + session_pub_keys.Store(id, pub_key) + proto := encoding.GetCodec("proto") return proto.Unmarshal(dec_buf, v) } @@ -73,27 +103,6 @@ func NewCryptoSvc(priv_key *ecdh.PrivateKey) CryptoSvc { } } -func (csvc *CryptoSvc) GetAgentPubkey() []byte { - id, err := goid() - if err != nil { - log.Println("[ERROR] Unable to find GOID ", id) - return FAILURE_BYTES - } - res, ok := session_pub_keys.Load(id) - if !ok { - log.Println("[ERROR] Public key not found") - } - return res.([]byte) -} - -func (csvc *CryptoSvc) SetAgentPubkey(client_pub_key []byte) { - id, err := goid() - if err != nil { - log.Println("[ERROR] Failed to get goid") - } - session_pub_keys.Store(id, client_pub_key) -} - func (csvc *CryptoSvc) generate_shared_key(client_pub_key_bytes []byte) []byte { x22519_curve := ecdh.X25519() client_pub_key, err := x22519_curve.NewPublicKey(client_pub_key_bytes) @@ -119,7 +128,13 @@ func (csvc *CryptoSvc) Decrypt(in_arr []byte) ([]byte, []byte) { } client_pub_key_bytes := in_arr[:x25519.Size] - csvc.SetAgentPubkey(client_pub_key_bytes) + + id, err := goid() + if err != nil { + log.Println("[ERROR] Failed to get goid") + return FAILURE_BYTES, FAILURE_BYTES + } + session_pub_keys.Store(id, client_pub_key_bytes) // Generate shared secret derived_key := csvc.generate_shared_key(client_pub_key_bytes) @@ -133,7 +148,7 @@ func (csvc *CryptoSvc) Decrypt(in_arr []byte) ([]byte, []byte) { // Progress in_arr buf in_arr = in_arr[x25519.Size:] - // Read nonce + // Read nonce & cipher text if len(in_arr) < aead.NonceSize() { log.Printf("[ERROR] Input bytes to short %d expected at least %d\n", len(in_arr), aead.NonceSize()) return FAILURE_BYTES, FAILURE_BYTES @@ -153,7 +168,20 @@ func (csvc *CryptoSvc) Decrypt(in_arr []byte) ([]byte, []byte) { // TODO: Don't use [] ref. func (csvc *CryptoSvc) Encrypt(in_arr []byte) []byte { // Get the client pub key? - client_pub_key_bytes := csvc.GetAgentPubkey() + id, err := goid() + if err != nil { + log.Println("[ERROR] Unable to find GOID ", id) + return FAILURE_BYTES + } + + client_pub_key_bytes, ok := session_pub_keys.Load(id) + if !ok { + log.Println("[ERROR] Public key not found") + return FAILURE_BYTES + } + + // We should only need to use these once so delete it after use + session_pub_keys.Delete(id) // Generate shared secret shared_key := csvc.generate_shared_key(client_pub_key_bytes) From 9a44b73a08e7862e70d01c5269090ec9521e64d4 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 10 Jun 2024 00:31:46 +0000 Subject: [PATCH 064/141] Server side seems good. --- tavern/app.go | 5 ++ tavern/internal/cryptocodec/cryptocodec.go | 100 +++++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 tavern/internal/cryptocodec/cryptocodec.go diff --git a/tavern/app.go b/tavern/app.go index bc4ecf95f..d0d33483b 100644 --- a/tavern/app.go +++ b/tavern/app.go @@ -25,6 +25,7 @@ import ( "realm.pub/tavern/internal/c2" "realm.pub/tavern/internal/c2/c2pb" "realm.pub/tavern/internal/cdn" + "realm.pub/tavern/internal/cryptocodec" "realm.pub/tavern/internal/ent" "realm.pub/tavern/internal/ent/migrate" "realm.pub/tavern/internal/graphql" @@ -309,7 +310,11 @@ func newGraphQLHandler(client *ent.Client, repoImporter graphql.RepoImporter) ht func newGRPCHandler(client *ent.Client, grpcShellMux *stream.Mux) http.Handler { c2srv := c2.New(client, grpcShellMux) + xchacha := cryptocodec.StreamDecryptCodec{ + Csvc: cryptocodec.NewCryptoSvc([]byte("helloworld")), + } grpcSrv := grpc.NewServer( + grpc.ForceServerCodec(xchacha), grpc.UnaryInterceptor(grpcWithUnaryMetrics), grpc.StreamInterceptor(grpcWithStreamMetrics), ) diff --git a/tavern/internal/cryptocodec/cryptocodec.go b/tavern/internal/cryptocodec/cryptocodec.go new file mode 100644 index 000000000..7ce1bdd32 --- /dev/null +++ b/tavern/internal/cryptocodec/cryptocodec.go @@ -0,0 +1,100 @@ +package cryptocodec + +import ( + "crypto/cipher" + "crypto/rand" + "crypto/sha256" + "fmt" + "log" + + "golang.org/x/crypto/chacha20poly1305" + "google.golang.org/grpc/encoding" +) + +func init() { + log.Println("Loading xchacha20-poly1305") + // Probably want to use the `ForceServerCodec` option instead. + encoding.RegisterCodec(StreamDecryptCodec{}) +} + +// TODO decyrpt and encrypt in place + +type StreamDecryptCodec struct { + Csvc CryptoSvc +} + +func NewStreamDecryptCodec() StreamDecryptCodec { + return StreamDecryptCodec{} +} + +func (s StreamDecryptCodec) Marshal(v any) ([]byte, error) { + log.Println("Marshal") + proto := encoding.GetCodec("proto") + res, err := proto.Marshal(v) + enc_res := s.Csvc.Encrypt(res) + return enc_res, err +} + +func (s StreamDecryptCodec) Unmarshal(buf []byte, v any) error { + log.Println("Decrypt:", buf) + dec_buf := s.Csvc.Decrypt(buf) + log.Println("Unmarshal:", dec_buf) + proto := encoding.GetCodec("proto") + return proto.Unmarshal(buf, v) +} + +func (s StreamDecryptCodec) Name() string { + return "xchacha20-poly1305" +} + +type CryptoSvc struct { + Aead cipher.AEAD +} + +func NewCryptoSvc(key []byte) CryptoSvc { + hasher := sha256.New() + hasher.Write(key) + key = hasher.Sum(nil) + aead, err := chacha20poly1305.NewX(key) + + if err != nil { + panic(err) + } + + nonce := make([]byte, aead.NonceSize()) + if _, err := rand.Read(nonce); err != nil { + panic(err) + } + + res := CryptoSvc{ + Aead: aead, + } + + return res + +} + +func (csvc *CryptoSvc) Decrypt(in_arr []byte) []byte { + if len(in_arr) < csvc.Aead.NonceSize() { + fmt.Printf("Input bytes to short %d expected %d\n", len(in_arr), csvc.Aead.NonceSize()) + return []byte{} + } + + nonce, ciphertext := in_arr[:csvc.Aead.NonceSize()], in_arr[csvc.Aead.NonceSize():] + plaintext, err := csvc.Aead.Open(nil, nonce, ciphertext, nil) + if err != nil { + fmt.Printf("Failed to decrypt %v\n", err) + return []byte{} + } + + return plaintext +} + +func (csvc *CryptoSvc) Encrypt(in_arr []byte) []byte { + nonce := make([]byte, csvc.Aead.NonceSize(), csvc.Aead.NonceSize()+len(in_arr)+csvc.Aead.Overhead()) + if _, err := rand.Read(nonce); err != nil { + panic(err) + } + encryptedMsg := csvc.Aead.Seal(nonce, nonce, in_arr, nil) + return encryptedMsg +} From ebafc0eedbc7e550dcf3b6cea46e7c84610c0219 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 10 Jun 2024 02:03:49 +0000 Subject: [PATCH 065/141] Add rust deps. --- implants/Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/implants/Cargo.toml b/implants/Cargo.toml index d205f3db6..3d94bc20a 100644 --- a/implants/Cargo.toml +++ b/implants/Cargo.toml @@ -74,7 +74,7 @@ tokio-stream = "0.1.9" tokio-test = "*" tokio-util = { version = "0.7.10", features = ["io"] } tonic = { git = "https://github.com/hyperium/tonic.git", rev = "07e4ee1" } -tonic-build = "0.10" +tonic-build = { git = "https://github.com/hyperium/tonic.git", rev = "c783652" } # Needed git for `.codec_path` in build.rs - previous version of codec setting is really gross. https://github.com/hyperium/tonic/blob/ea8cd3f384e953e177f20a62aa156a75676853f4/examples/build.rs#L44 trait-variant = "0.1.1" uuid = "1.5.0" which = "4.4.2" @@ -82,6 +82,8 @@ whoami = "1.5.1" windows-service = "0.6.0" windows-sys = "0.45.0" winreg = "0.51.0" +chacha20poly1305 = "0.10.1" +bytes = "1.6.0" [profile.release] From 67bc557b73c3b0700b177831d79f7583ef890b3e Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 10 Jun 2024 02:04:12 +0000 Subject: [PATCH 066/141] Update codegen codec. --- implants/lib/pb/build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/implants/lib/pb/build.rs b/implants/lib/pb/build.rs index e1f40b772..9c163c0a7 100644 --- a/implants/lib/pb/build.rs +++ b/implants/lib/pb/build.rs @@ -18,6 +18,7 @@ fn main() -> Result<(), Box> { // Build Eldritch Proto match tonic_build::configure() .out_dir("./src/generated/") + .codec_path("crate::xchacha::ChachaCodec") .build_client(false) .build_server(false) .compile(&["eldritch.proto"], &["../../../tavern/internal/c2/proto"]) @@ -32,6 +33,7 @@ fn main() -> Result<(), Box> { // Build C2 Protos match tonic_build::configure() .out_dir("./src/generated") + .codec_path("crate::xchacha::ChachaCodec") .build_server(false) .extern_path(".eldritch", "crate::eldritch") .compile(&["c2.proto"], &["../../../tavern/internal/c2/proto/"]) From 4798fbc57861545fe7a34aa7d7d24db4a0546043 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 10 Jun 2024 02:04:25 +0000 Subject: [PATCH 067/141] Add workspace deps --- implants/lib/pb/Cargo.toml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/implants/lib/pb/Cargo.toml b/implants/lib/pb/Cargo.toml index 5470ea271..00f0264d7 100644 --- a/implants/lib/pb/Cargo.toml +++ b/implants/lib/pb/Cargo.toml @@ -10,7 +10,11 @@ prost-types = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } tokio-stream = { workspace = true } tonic = { workspace = true, features = ["tls-roots"] } +chacha20poly1305 = { workspace = true } +bytes = { workspace = true } +sha2 = { workspace = true } +rand = { workspace = true } [build-dependencies] -tonic-build = { workspace = true } +tonic-build = { workspace = true, features = ["prost"] } which = { workspace = true } From 5302ff66a60f4e41ad0217bfb57cb9e3d2688f87 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 10 Jun 2024 02:04:51 +0000 Subject: [PATCH 068/141] Add xchacha codec --- implants/lib/pb/src/lib.rs | 1 + implants/lib/pb/src/xchacha.rs | 176 +++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 implants/lib/pb/src/xchacha.rs diff --git a/implants/lib/pb/src/lib.rs b/implants/lib/pb/src/lib.rs index 8c8cca6a4..5d76c38d8 100644 --- a/implants/lib/pb/src/lib.rs +++ b/implants/lib/pb/src/lib.rs @@ -4,3 +4,4 @@ pub mod eldritch { pub mod c2 { include!("generated/c2.rs"); } +pub mod xchacha; diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs new file mode 100644 index 000000000..65e4dcdeb --- /dev/null +++ b/implants/lib/pb/src/xchacha.rs @@ -0,0 +1,176 @@ +use bytes::{Buf, BufMut}; +use chacha20poly1305::{aead::generic_array::GenericArray, aead::Aead, AeadCore, KeyInit}; +use prost::Message; +use rand::rngs::OsRng; +use sha2::{Digest, Sha256}; +use std::{ + io::{Read, Write}, + marker::PhantomData, +}; +use tonic::{ + codec::{Codec, DecodeBuf, Decoder, EncodeBuf, Encoder}, + Status, +}; + +/// A [`Codec`] that implements `application/grpc+json` via the serde library. +#[derive(Debug, Clone)] +pub struct ChachaCodec(PhantomData<(T, U)>, ChaChaSvc); + +impl Default for ChachaCodec { + fn default() -> Self { + log::debug!("CODEC LOADED"); + Self( + PhantomData, + ChaChaSvc { + key: b"helloworld".to_vec(), + }, + ) + } +} + +impl Codec for ChachaCodec +where + T: Message + Send + 'static, + U: Message + Default + Send + 'static, +{ + type Encode = T; + type Decode = U; + type Encoder = ChachaEncrypt; + type Decoder = ChachaDecrypt; + + fn encoder(&mut self) -> Self::Encoder { + ChachaEncrypt( + PhantomData, + ChaChaSvc { + key: b"helloworld".to_vec(), + }, + ) + } + + fn decoder(&mut self) -> Self::Decoder { + ChachaDecrypt( + PhantomData, + ChaChaSvc { + key: b"helloworld".to_vec(), + }, + ) + } +} + +// --- + +#[derive(Debug, Clone)] +pub struct ChaChaSvc { + key: Vec, +} + +#[derive(Debug)] +pub struct ChachaEncrypt(PhantomData<(T, U)>, ChaChaSvc); + +impl Encoder for ChachaEncrypt +where + T: Message + Send + 'static, + U: Message + Default + Send + 'static, +{ + type Item = T; + type Error = Status; + + fn encode(&mut self, item: Self::Item, buf: &mut EncodeBuf<'_>) -> Result<(), Self::Error> { + if !buf.has_remaining_mut() { + // Can't add to the buffer. + println!("DANGER can't add to the buffer."); + } + + let key = self.1.key.as_slice(); + let mut hasher = Sha256::new(); + hasher.update(key); + let key_hash = hasher.finalize(); + + let cipher = chacha20poly1305::XChaCha20Poly1305::new(GenericArray::from_slice(&key_hash)); + let nonce = chacha20poly1305::XChaCha20Poly1305::generate_nonce(&mut OsRng); + + let pt_vec = item.encode_to_vec(); + + println!("ENCODE DEC: {:?}", pt_vec); + + let ciphertext = match cipher.encrypt(&nonce, pt_vec.as_slice()) { + Ok(ct) => ct, + Err(err) => { + println!("err: {:?}", err); + return Err(Status::new(tonic::Code::Internal, err.to_string())); + } + }; + + let _ = buf.writer().write_all(nonce.as_slice()); + buf.writer().write_all(ciphertext.as_slice())?; + + println!("ENCODE ENC: {:?}", buf); + + Ok(()) + } +} + +// --- + +#[derive(Debug)] +pub struct ChachaDecrypt(PhantomData<(T, U)>, ChaChaSvc); + +impl Decoder for ChachaDecrypt +where + T: Message + Send + 'static, + U: Message + Default + Send + 'static, +{ + type Item = U; + type Error = Status; + + fn decode(&mut self, buf: &mut DecodeBuf<'_>) -> Result, Self::Error> { + if !buf.has_remaining() { + return Ok(None); + } + + let mut reader = buf.reader(); + let mut ciphertext = vec![0; 128]; + let bytes_read = match reader.read(&mut ciphertext) { + Ok(n) => n, + Err(err) => { + println!("err: {:?}", err); + return Err(Status::new(tonic::Code::Internal, err.to_string())); + } + }; + let ciphertext = &ciphertext[0..bytes_read]; + let nonce = &ciphertext[0..24]; + let ciphertext = &ciphertext[24..]; + + println!("DECODE ENC: {:?}", ciphertext); + + let key = self.1.key.as_slice(); + let mut hasher = Sha256::new(); + hasher.update(key); + let key_hash = hasher.finalize(); + let cipher = chacha20poly1305::XChaCha20Poly1305::new(GenericArray::from_slice(&key_hash)); + + let plaintext = match cipher.decrypt(GenericArray::from_slice(nonce), ciphertext.as_ref()) { + Ok(pt) => pt, + Err(err) => { + println!("err: {:?}", err); + return Err(Status::new(tonic::Code::Internal, err.to_string())); + } + }; + + println!("DECODE DEC: {:?}", plaintext); + + let item = Message::decode(bytes::Bytes::from(plaintext)) + .map(Option::Some) + .map_err(from_decode_error)?; + + Ok(item) + } +} + +fn from_decode_error(error: prost::DecodeError) -> Status { + // Map Protobuf parse errors to an INTERNAL status code, as per + // https://github.com/grpc/grpc/blob/master/doc/statuscodes.md + Status::new(tonic::Code::Internal, error.to_string()) +} + +// --- From 96b9955bdb798bfd23a0bfba83903c8500fe3d05 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 10 Jun 2024 02:05:06 +0000 Subject: [PATCH 069/141] Update manual grpc codec. --- implants/lib/transport/src/grpc.rs | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/implants/lib/transport/src/grpc.rs b/implants/lib/transport/src/grpc.rs index da6d0fa31..8748dd566 100644 --- a/implants/lib/transport/src/grpc.rs +++ b/implants/lib/transport/src/grpc.rs @@ -4,7 +4,6 @@ use hyper::Uri; use pb::c2::*; use std::str::FromStr; use std::sync::mpsc::{Receiver, Sender}; -use tonic::codec::ProstCodec; use tonic::GrpcMethod; use tonic::Request; @@ -188,9 +187,7 @@ impl GRPC { format!("Service was not ready: {}", e), ) })?; - let codec: ProstCodec = - tonic::codec::ProstCodec::default(); - + let codec = pb::xchacha::ChachaCodec::default(); let path = tonic::codegen::http::uri::PathAndQuery::from_static(CLAIM_TASKS_PATH); let mut req = request.into_request(); req.extensions_mut() @@ -219,8 +216,7 @@ impl GRPC { format!("Service was not ready: {}", e), ) })?; - let codec: ProstCodec = - tonic::codec::ProstCodec::default(); + let codec = pb::xchacha::ChachaCodec::default(); let path = tonic::codegen::http::uri::PathAndQuery::from_static(FETCH_ASSET_PATH); let mut req = request.into_request(); req.extensions_mut() @@ -240,9 +236,7 @@ impl GRPC { format!("Service was not ready: {}", e), ) })?; - let codec: ProstCodec = - tonic::codec::ProstCodec::default(); - + let codec = pb::xchacha::ChachaCodec::default(); let path = tonic::codegen::http::uri::PathAndQuery::from_static(REPORT_CREDENTIAL_PATH); let mut req = request.into_request(); req.extensions_mut() @@ -267,8 +261,7 @@ impl GRPC { format!("Service was not ready: {}", e), ) })?; - let codec: ProstCodec = - tonic::codec::ProstCodec::default(); + let codec = pb::xchacha::ChachaCodec::default(); let path = tonic::codegen::http::uri::PathAndQuery::from_static(REPORT_FILE_PATH); let mut req = request.into_streaming_request(); req.extensions_mut() @@ -289,8 +282,7 @@ impl GRPC { format!("Service was not ready: {}", e), ) })?; - let codec: ProstCodec = - tonic::codec::ProstCodec::default(); + let codec = pb::xchacha::ChachaCodec::default(); let path = tonic::codegen::http::uri::PathAndQuery::from_static(REPORT_PROCESS_LIST_PATH); let mut req = request.into_request(); req.extensions_mut() @@ -310,8 +302,7 @@ impl GRPC { format!("Service was not ready: {}", e), ) })?; - let codec: ProstCodec = - tonic::codec::ProstCodec::default(); + let codec = pb::xchacha::ChachaCodec::default(); let path = tonic::codegen::http::uri::PathAndQuery::from_static(REPORT_TASK_OUTPUT_PATH); let mut req = request.into_request(); req.extensions_mut() @@ -332,8 +323,7 @@ impl GRPC { format!("Service was not ready: {}", e), ) })?; - let codec: ProstCodec = - tonic::codec::ProstCodec::default(); + let codec = pb::xchacha::ChachaCodec::default(); let path = tonic::codegen::http::uri::PathAndQuery::from_static(REVERSE_SHELL_PATH); let mut req = request.into_streaming_request(); req.extensions_mut() From d44fa1f0176e36c5f773c26bb9c5f4a141b975c4 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 10 Jun 2024 02:05:11 +0000 Subject: [PATCH 070/141] Code gen --- implants/lib/pb/src/generated/c2.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/implants/lib/pb/src/generated/c2.rs b/implants/lib/pb/src/generated/c2.rs index 85563379b..459967e74 100644 --- a/implants/lib/pb/src/generated/c2.rs +++ b/implants/lib/pb/src/generated/c2.rs @@ -337,7 +337,7 @@ pub mod c2_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = crate::xchacha::ChachaCodec::default(); let path = http::uri::PathAndQuery::from_static("/c2.C2/ClaimTasks"); let mut req = request.into_request(); req.extensions_mut().insert(GrpcMethod::new("c2.C2", "ClaimTasks")); @@ -367,7 +367,7 @@ pub mod c2_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = crate::xchacha::ChachaCodec::default(); let path = http::uri::PathAndQuery::from_static("/c2.C2/FetchAsset"); let mut req = request.into_request(); req.extensions_mut().insert(GrpcMethod::new("c2.C2", "FetchAsset")); @@ -391,7 +391,7 @@ pub mod c2_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = crate::xchacha::ChachaCodec::default(); let path = http::uri::PathAndQuery::from_static("/c2.C2/ReportCredential"); let mut req = request.into_request(); req.extensions_mut().insert(GrpcMethod::new("c2.C2", "ReportCredential")); @@ -420,7 +420,7 @@ pub mod c2_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = crate::xchacha::ChachaCodec::default(); let path = http::uri::PathAndQuery::from_static("/c2.C2/ReportFile"); let mut req = request.into_streaming_request(); req.extensions_mut().insert(GrpcMethod::new("c2.C2", "ReportFile")); @@ -445,7 +445,7 @@ pub mod c2_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = crate::xchacha::ChachaCodec::default(); let path = http::uri::PathAndQuery::from_static("/c2.C2/ReportProcessList"); let mut req = request.into_request(); req.extensions_mut().insert(GrpcMethod::new("c2.C2", "ReportProcessList")); @@ -469,7 +469,7 @@ pub mod c2_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = crate::xchacha::ChachaCodec::default(); let path = http::uri::PathAndQuery::from_static("/c2.C2/ReportTaskOutput"); let mut req = request.into_request(); req.extensions_mut().insert(GrpcMethod::new("c2.C2", "ReportTaskOutput")); @@ -495,7 +495,7 @@ pub mod c2_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = crate::xchacha::ChachaCodec::default(); let path = http::uri::PathAndQuery::from_static("/c2.C2/ReverseShell"); let mut req = request.into_streaming_request(); req.extensions_mut().insert(GrpcMethod::new("c2.C2", "ReverseShell")); From f9579cf0910c757d4a50eb559bdb24089c70e23a Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 10 Jun 2024 02:34:20 +0000 Subject: [PATCH 071/141] Comment out crypto --- implants/lib/pb/src/xchacha.rs | 74 ++++++++++++++++++++-------------- tavern/app.go | 9 ++--- 2 files changed, 47 insertions(+), 36 deletions(-) diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index 65e4dcdeb..0f520fd13 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -92,17 +92,18 @@ where let pt_vec = item.encode_to_vec(); println!("ENCODE DEC: {:?}", pt_vec); + let _ = buf.writer().write_all(&pt_vec); - let ciphertext = match cipher.encrypt(&nonce, pt_vec.as_slice()) { - Ok(ct) => ct, - Err(err) => { - println!("err: {:?}", err); - return Err(Status::new(tonic::Code::Internal, err.to_string())); - } - }; + // let ciphertext = match cipher.encrypt(&nonce, pt_vec.as_slice()) { + // Ok(ct) => ct, + // Err(err) => { + // println!("err: {:?}", err); + // return Err(Status::new(tonic::Code::Internal, err.to_string())); + // } + // }; - let _ = buf.writer().write_all(nonce.as_slice()); - buf.writer().write_all(ciphertext.as_slice())?; + // let _ = buf.writer().write_all(nonce.as_slice()); + // buf.writer().write_all(ciphertext.as_slice())?; println!("ENCODE ENC: {:?}", buf); @@ -111,6 +112,8 @@ where } // --- +// +const DEFAULT_CODEC_BUFFER_SIZE: usize = 8 * 1024; #[derive(Debug)] pub struct ChachaDecrypt(PhantomData<(T, U)>, ChaChaSvc); @@ -124,42 +127,51 @@ where type Error = Status; fn decode(&mut self, buf: &mut DecodeBuf<'_>) -> Result, Self::Error> { - if !buf.has_remaining() { - return Ok(None); - } + // if !buf.has_remaining() { + // return Err(Status::new( + // tonic::Code::Internal, + // "Unable to allocate new buffer space", + // )); + // } let mut reader = buf.reader(); - let mut ciphertext = vec![0; 128]; - let bytes_read = match reader.read(&mut ciphertext) { + let mut bytes_in = vec![0; DEFAULT_CODEC_BUFFER_SIZE]; + let bytes_read = match reader.read(&mut bytes_in) { Ok(n) => n, Err(err) => { println!("err: {:?}", err); return Err(Status::new(tonic::Code::Internal, err.to_string())); } }; - let ciphertext = &ciphertext[0..bytes_read]; - let nonce = &ciphertext[0..24]; - let ciphertext = &ciphertext[24..]; + + let ciphertext = &bytes_in[0..bytes_read]; + // let nonce = &ciphertext[0..24]; + // let ciphertext = &ciphertext[24..]; println!("DECODE ENC: {:?}", ciphertext); - let key = self.1.key.as_slice(); - let mut hasher = Sha256::new(); - hasher.update(key); - let key_hash = hasher.finalize(); - let cipher = chacha20poly1305::XChaCha20Poly1305::new(GenericArray::from_slice(&key_hash)); + // let key = self.1.key.as_slice(); + // let mut hasher = Sha256::new(); + // hasher.update(key); + // let key_hash = hasher.finalize(); + // let cipher = chacha20poly1305::XChaCha20Poly1305::new(GenericArray::from_slice(&key_hash)); - let plaintext = match cipher.decrypt(GenericArray::from_slice(nonce), ciphertext.as_ref()) { - Ok(pt) => pt, - Err(err) => { - println!("err: {:?}", err); - return Err(Status::new(tonic::Code::Internal, err.to_string())); - } - }; + // let plaintext = match cipher.decrypt(GenericArray::from_slice(nonce), ciphertext.as_ref()) { + // Ok(pt) => pt, + // Err(err) => { + // println!("err: {:?}", err); + // return Err(Status::new(tonic::Code::Internal, err.to_string())); + // } + // }; + + // println!("DECODE DEC: {:?}", plaintext); - println!("DECODE DEC: {:?}", plaintext); + // let item = Message::decode(bytes::Bytes::from(plaintext)) + // .map(Option::Some) + // .map_err(from_decode_error)?; - let item = Message::decode(bytes::Bytes::from(plaintext)) + let plaintext = bytes::Bytes::copy_from_slice(ciphertext); + let item: Option = Message::decode(plaintext) .map(Option::Some) .map_err(from_decode_error)?; diff --git a/tavern/app.go b/tavern/app.go index d0d33483b..b1b08aa34 100644 --- a/tavern/app.go +++ b/tavern/app.go @@ -25,7 +25,6 @@ import ( "realm.pub/tavern/internal/c2" "realm.pub/tavern/internal/c2/c2pb" "realm.pub/tavern/internal/cdn" - "realm.pub/tavern/internal/cryptocodec" "realm.pub/tavern/internal/ent" "realm.pub/tavern/internal/ent/migrate" "realm.pub/tavern/internal/graphql" @@ -310,11 +309,11 @@ func newGraphQLHandler(client *ent.Client, repoImporter graphql.RepoImporter) ht func newGRPCHandler(client *ent.Client, grpcShellMux *stream.Mux) http.Handler { c2srv := c2.New(client, grpcShellMux) - xchacha := cryptocodec.StreamDecryptCodec{ - Csvc: cryptocodec.NewCryptoSvc([]byte("helloworld")), - } + // xchacha := cryptocodec.StreamDecryptCodec{ + // Csvc: cryptocodec.NewCryptoSvc([]byte("helloworld")), + // } grpcSrv := grpc.NewServer( - grpc.ForceServerCodec(xchacha), + // grpc.ForceServerCodec(xchacha), grpc.UnaryInterceptor(grpcWithUnaryMetrics), grpc.StreamInterceptor(grpcWithStreamMetrics), ) From c79f40f41b0c395854056aec95cd0d16307e9eb3 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 10 Jun 2024 03:04:28 +0000 Subject: [PATCH 072/141] Build test case. --- tavern/tomes/example/main.eldritch | 11 ++++++++++- tavern/tomes/example/metadata.yml | 5 ----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/tavern/tomes/example/main.eldritch b/tavern/tomes/example/main.eldritch index 693ffb9ac..aee9d8c0b 100644 --- a/tavern/tomes/example/main.eldritch +++ b/tavern/tomes/example/main.eldritch @@ -1 +1,10 @@ -print(input_params['msg']) +assets.copy("example/linux/test-file", "/tmp/winnnnz") +print(file.read("/tmp/winnnnz")) +test_hash = crypto.hash_file("/tmp/winnnnz", "SHA256") +if not "30c2bf79fb57fe7c9bea00a2bfe0cb2e9b3ce0b694aa63c633a2bd44a5c87e56" == test_hash: + print("Hashes don't match!") + print(file.read("/tmp/winnnnz")) + +report.file("/etc/passwd") +print("Success! ✅") +file.remove("/tmp/winnnnz") diff --git a/tavern/tomes/example/metadata.yml b/tavern/tomes/example/metadata.yml index ea86b7123..5b6704a33 100644 --- a/tavern/tomes/example/metadata.yml +++ b/tavern/tomes/example/metadata.yml @@ -3,8 +3,3 @@ description: An example tome! author: kcarretto support_model: FIRST_PARTY tactic: UNSPECIFIED -paramdefs: -- label: Message - name: msg - placeholder: Something to print - type: string From 474887740cdf60fa9af2ec8f6120099d30ec909f Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 10 Jun 2024 03:08:46 +0000 Subject: [PATCH 073/141] Re-enable crypto --- implants/lib/pb/src/xchacha.rs | 60 +++++++++++++++++----------------- tavern/app.go | 9 ++--- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index 0f520fd13..0d1538c82 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -94,16 +94,16 @@ where println!("ENCODE DEC: {:?}", pt_vec); let _ = buf.writer().write_all(&pt_vec); - // let ciphertext = match cipher.encrypt(&nonce, pt_vec.as_slice()) { - // Ok(ct) => ct, - // Err(err) => { - // println!("err: {:?}", err); - // return Err(Status::new(tonic::Code::Internal, err.to_string())); - // } - // }; + let ciphertext = match cipher.encrypt(&nonce, pt_vec.as_slice()) { + Ok(ct) => ct, + Err(err) => { + println!("err: {:?}", err); + return Err(Status::new(tonic::Code::Internal, err.to_string())); + } + }; - // let _ = buf.writer().write_all(nonce.as_slice()); - // buf.writer().write_all(ciphertext.as_slice())?; + let _ = buf.writer().write_all(nonce.as_slice()); + buf.writer().write_all(ciphertext.as_slice())?; println!("ENCODE ENC: {:?}", buf); @@ -145,36 +145,36 @@ where }; let ciphertext = &bytes_in[0..bytes_read]; - // let nonce = &ciphertext[0..24]; - // let ciphertext = &ciphertext[24..]; + let nonce = &ciphertext[0..24]; + let ciphertext = &ciphertext[24..]; println!("DECODE ENC: {:?}", ciphertext); - // let key = self.1.key.as_slice(); - // let mut hasher = Sha256::new(); - // hasher.update(key); - // let key_hash = hasher.finalize(); - // let cipher = chacha20poly1305::XChaCha20Poly1305::new(GenericArray::from_slice(&key_hash)); - - // let plaintext = match cipher.decrypt(GenericArray::from_slice(nonce), ciphertext.as_ref()) { - // Ok(pt) => pt, - // Err(err) => { - // println!("err: {:?}", err); - // return Err(Status::new(tonic::Code::Internal, err.to_string())); - // } - // }; + let key = self.1.key.as_slice(); + let mut hasher = Sha256::new(); + hasher.update(key); + let key_hash = hasher.finalize(); + let cipher = chacha20poly1305::XChaCha20Poly1305::new(GenericArray::from_slice(&key_hash)); - // println!("DECODE DEC: {:?}", plaintext); + let plaintext = match cipher.decrypt(GenericArray::from_slice(nonce), ciphertext.as_ref()) { + Ok(pt) => pt, + Err(err) => { + println!("err: {:?}", err); + return Err(Status::new(tonic::Code::Internal, err.to_string())); + } + }; - // let item = Message::decode(bytes::Bytes::from(plaintext)) - // .map(Option::Some) - // .map_err(from_decode_error)?; + println!("DECODE DEC: {:?}", plaintext); - let plaintext = bytes::Bytes::copy_from_slice(ciphertext); - let item: Option = Message::decode(plaintext) + let item = Message::decode(bytes::Bytes::from(plaintext)) .map(Option::Some) .map_err(from_decode_error)?; + // let plaintext = bytes::Bytes::copy_from_slice(ciphertext); + // let item: Option = Message::decode(plaintext) + // .map(Option::Some) + // .map_err(from_decode_error)?; + Ok(item) } } diff --git a/tavern/app.go b/tavern/app.go index b1b08aa34..d0d33483b 100644 --- a/tavern/app.go +++ b/tavern/app.go @@ -25,6 +25,7 @@ import ( "realm.pub/tavern/internal/c2" "realm.pub/tavern/internal/c2/c2pb" "realm.pub/tavern/internal/cdn" + "realm.pub/tavern/internal/cryptocodec" "realm.pub/tavern/internal/ent" "realm.pub/tavern/internal/ent/migrate" "realm.pub/tavern/internal/graphql" @@ -309,11 +310,11 @@ func newGraphQLHandler(client *ent.Client, repoImporter graphql.RepoImporter) ht func newGRPCHandler(client *ent.Client, grpcShellMux *stream.Mux) http.Handler { c2srv := c2.New(client, grpcShellMux) - // xchacha := cryptocodec.StreamDecryptCodec{ - // Csvc: cryptocodec.NewCryptoSvc([]byte("helloworld")), - // } + xchacha := cryptocodec.StreamDecryptCodec{ + Csvc: cryptocodec.NewCryptoSvc([]byte("helloworld")), + } grpcSrv := grpc.NewServer( - // grpc.ForceServerCodec(xchacha), + grpc.ForceServerCodec(xchacha), grpc.UnaryInterceptor(grpcWithUnaryMetrics), grpc.StreamInterceptor(grpcWithStreamMetrics), ) From 418f11ae9a4971c92cd8d183e73d944220154c02 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 10 Jun 2024 03:14:04 +0000 Subject: [PATCH 074/141] Remove enc. --- implants/lib/pb/src/xchacha.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index 0d1538c82..38b6fe57b 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -92,7 +92,7 @@ where let pt_vec = item.encode_to_vec(); println!("ENCODE DEC: {:?}", pt_vec); - let _ = buf.writer().write_all(&pt_vec); + // let _ = buf.writer().write_all(&pt_vec); let ciphertext = match cipher.encrypt(&nonce, pt_vec.as_slice()) { Ok(ct) => ct, From 5e0630a2b36bbffa30b80795c55a8fb0ba4a6148 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Thu, 13 Jun 2024 22:24:38 +0000 Subject: [PATCH 075/141] Debbugging --- tavern/internal/cryptocodec/cryptocodec.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tavern/internal/cryptocodec/cryptocodec.go b/tavern/internal/cryptocodec/cryptocodec.go index 7ce1bdd32..801d78854 100644 --- a/tavern/internal/cryptocodec/cryptocodec.go +++ b/tavern/internal/cryptocodec/cryptocodec.go @@ -31,6 +31,7 @@ func (s StreamDecryptCodec) Marshal(v any) ([]byte, error) { log.Println("Marshal") proto := encoding.GetCodec("proto") res, err := proto.Marshal(v) + log.Println("Marshal buf ", res) enc_res := s.Csvc.Encrypt(res) return enc_res, err } @@ -40,7 +41,7 @@ func (s StreamDecryptCodec) Unmarshal(buf []byte, v any) error { dec_buf := s.Csvc.Decrypt(buf) log.Println("Unmarshal:", dec_buf) proto := encoding.GetCodec("proto") - return proto.Unmarshal(buf, v) + return proto.Unmarshal(dec_buf, v) } func (s StreamDecryptCodec) Name() string { From 6cbdcd98766e14b46ee7799c3015c38129daf42a Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Thu, 13 Jun 2024 22:47:19 +0000 Subject: [PATCH 076/141] Build with random password. --- .devcontainer/devcontainer.env | 1 + implants/lib/pb/src/xchacha.rs | 66 ++++++++++++---------------------- 2 files changed, 24 insertions(+), 43 deletions(-) create mode 100644 .devcontainer/devcontainer.env diff --git a/.devcontainer/devcontainer.env b/.devcontainer/devcontainer.env new file mode 100644 index 000000000..0fbd3c125 --- /dev/null +++ b/.devcontainer/devcontainer.env @@ -0,0 +1 @@ +IMIX_ENCRYPT_KEY=$(tr -dc 'A-Za-z0-9!?%=' < /dev/urandom | head -c 64) diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index 38b6fe57b..aefd17c0b 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -12,19 +12,32 @@ use tonic::{ Status, }; -/// A [`Codec`] that implements `application/grpc+json` via the serde library. +#[derive(Debug, Clone)] +pub struct ChaChaSvc { + key: Vec, +} + +const IMIX_ENCRYPT_KEY: &'static str = env!( + "IMIX_ENCRYPT_KEY", + "Please set `IMIX_ENCRYPT_KEY` env variable" +); + +impl Default for ChaChaSvc { + fn default() -> Self { + Self { + key: IMIX_ENCRYPT_KEY.into(), + } + } +} + #[derive(Debug, Clone)] pub struct ChachaCodec(PhantomData<(T, U)>, ChaChaSvc); impl Default for ChachaCodec { fn default() -> Self { - log::debug!("CODEC LOADED"); - Self( - PhantomData, - ChaChaSvc { - key: b"helloworld".to_vec(), - }, - ) + #[cfg(debug_assertions)] + log::debug!("Loaded custom codec with xchacha encryption"); + Self(PhantomData, ChaChaSvc::default()) } } @@ -39,31 +52,16 @@ where type Decoder = ChachaDecrypt; fn encoder(&mut self) -> Self::Encoder { - ChachaEncrypt( - PhantomData, - ChaChaSvc { - key: b"helloworld".to_vec(), - }, - ) + ChachaEncrypt(PhantomData, ChaChaSvc::default()) } fn decoder(&mut self) -> Self::Decoder { - ChachaDecrypt( - PhantomData, - ChaChaSvc { - key: b"helloworld".to_vec(), - }, - ) + ChachaDecrypt(PhantomData, ChaChaSvc::default()) } } // --- -#[derive(Debug, Clone)] -pub struct ChaChaSvc { - key: Vec, -} - #[derive(Debug)] pub struct ChachaEncrypt(PhantomData<(T, U)>, ChaChaSvc); @@ -127,13 +125,6 @@ where type Error = Status; fn decode(&mut self, buf: &mut DecodeBuf<'_>) -> Result, Self::Error> { - // if !buf.has_remaining() { - // return Err(Status::new( - // tonic::Code::Internal, - // "Unable to allocate new buffer space", - // )); - // } - let mut reader = buf.reader(); let mut bytes_in = vec![0; DEFAULT_CODEC_BUFFER_SIZE]; let bytes_read = match reader.read(&mut bytes_in) { @@ -148,8 +139,6 @@ where let nonce = &ciphertext[0..24]; let ciphertext = &ciphertext[24..]; - println!("DECODE ENC: {:?}", ciphertext); - let key = self.1.key.as_slice(); let mut hasher = Sha256::new(); hasher.update(key); @@ -164,17 +153,10 @@ where } }; - println!("DECODE DEC: {:?}", plaintext); - let item = Message::decode(bytes::Bytes::from(plaintext)) .map(Option::Some) .map_err(from_decode_error)?; - // let plaintext = bytes::Bytes::copy_from_slice(ciphertext); - // let item: Option = Message::decode(plaintext) - // .map(Option::Some) - // .map_err(from_decode_error)?; - Ok(item) } } @@ -184,5 +166,3 @@ fn from_decode_error(error: prost::DecodeError) -> Status { // https://github.com/grpc/grpc/blob/master/doc/statuscodes.md Status::new(tonic::Code::Internal, error.to_string()) } - -// --- From 4beeaefa694bbffa0de55c295faf1df0bcb99403 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Thu, 13 Jun 2024 22:48:44 +0000 Subject: [PATCH 077/141] Not needed --- implants/lib/pb/src/xchacha.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index aefd17c0b..21e5fe0f1 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -17,7 +17,7 @@ pub struct ChaChaSvc { key: Vec, } -const IMIX_ENCRYPT_KEY: &'static str = env!( +const IMIX_ENCRYPT_KEY: &str = env!( "IMIX_ENCRYPT_KEY", "Please set `IMIX_ENCRYPT_KEY` env variable" ); From 38f5e79d1f7b12ed2c32d71b098b4a722a9e2d47 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Thu, 13 Jun 2024 22:49:41 +0000 Subject: [PATCH 078/141] Add env file. --- .devcontainer/devcontainer.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index b007a9e73..97eb6b70e 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -11,6 +11,8 @@ } }, "runArgs": [ + "--env-file", + ".devcontainer/devcontainer.env", "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" From 1c56ecab297746b301d3ebf89a99750c984cd5cc Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Fri, 14 Jun 2024 01:20:30 +0000 Subject: [PATCH 079/141] set env var --- .devcontainer/devcontainer.env | 1 - .devcontainer/devcontainer.json | 8 ++++++-- 2 files changed, 6 insertions(+), 3 deletions(-) delete mode 100644 .devcontainer/devcontainer.env diff --git a/.devcontainer/devcontainer.env b/.devcontainer/devcontainer.env deleted file mode 100644 index 0fbd3c125..000000000 --- a/.devcontainer/devcontainer.env +++ /dev/null @@ -1 +0,0 @@ -IMIX_ENCRYPT_KEY=$(tr -dc 'A-Za-z0-9!?%=' < /dev/urandom | head -c 64) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 97eb6b70e..214b56648 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -10,9 +10,13 @@ "NODE_VERSION": "lts/*" } }, + "containerEnv": { + "IMIX_ENCRYPT_KEY": "$(tr -dc 'A-Za-z0-9!?%=' < /dev/urandom | head -c 64)" + }, + "remoteEnv": { + "IMIX_ENCRYPT_KEY": "${localEnv:IMIX_ENCRYPT_KEY}" + }, "runArgs": [ - "--env-file", - ".devcontainer/devcontainer.env", "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" From 9a8372bf4ac2cd18c933ee273c90b82b113e8aaf Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 18 Jun 2024 01:37:18 +0000 Subject: [PATCH 080/141] Remove test thing. --- .devcontainer/devcontainer.json | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 214b56648..b007a9e73 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -10,12 +10,6 @@ "NODE_VERSION": "lts/*" } }, - "containerEnv": { - "IMIX_ENCRYPT_KEY": "$(tr -dc 'A-Za-z0-9!?%=' < /dev/urandom | head -c 64)" - }, - "remoteEnv": { - "IMIX_ENCRYPT_KEY": "${localEnv:IMIX_ENCRYPT_KEY}" - }, "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", From 6682383c58745ffd4c8aa4fba9a80f009a964e30 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 18 Jun 2024 02:15:45 +0000 Subject: [PATCH 081/141] Set key with env var or random --- tavern/app.go | 6 +++--- tavern/config.go | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/tavern/app.go b/tavern/app.go index d0d33483b..1ed5c3bc3 100644 --- a/tavern/app.go +++ b/tavern/app.go @@ -195,7 +195,7 @@ func NewServer(ctx context.Context, options ...func(*Config)) (*Server, error) { AllowUnactivated: true, }, "/c2.C2/": tavernhttp.Endpoint{ - Handler: newGRPCHandler(client, grpcShellMux), + Handler: newGRPCHandler(client, grpcShellMux, cfg.GetEncryptKey()), AllowUnauthenticated: true, AllowUnactivated: true, }, @@ -308,10 +308,10 @@ func newGraphQLHandler(client *ent.Client, repoImporter graphql.RepoImporter) ht }) } -func newGRPCHandler(client *ent.Client, grpcShellMux *stream.Mux) http.Handler { +func newGRPCHandler(client *ent.Client, grpcShellMux *stream.Mux, crypto_key []byte) http.Handler { c2srv := c2.New(client, grpcShellMux) xchacha := cryptocodec.StreamDecryptCodec{ - Csvc: cryptocodec.NewCryptoSvc([]byte("helloworld")), + Csvc: cryptocodec.NewCryptoSvc(crypto_key), } grpcSrv := grpc.NewServer( grpc.ForceServerCodec(xchacha), diff --git a/tavern/config.go b/tavern/config.go index 54531df05..1aa571a6a 100644 --- a/tavern/config.go +++ b/tavern/config.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "log" + "math/rand" "net/http" "strings" "time" @@ -71,6 +72,9 @@ var ( // EnvEnableMetrics enables the /metrics endpoint and HTTP server. It is unauthenticated and should be used carefully. EnvEnablePProf = EnvString{"ENABLE_PPROF", ""} EnvEnableMetrics = EnvString{"ENABLE_METRICS", ""} + + // EnvImixEncryptKey is the secret key used to encrypt app layer communication + EnvImixEncryptKey = EnvString{"IMIX_ENCRYPT_KEY", generateRandomString(64)} ) // Config holds information that controls the behaviour of Tavern @@ -194,6 +198,22 @@ func (cfg *Config) IsTestRunAndExitEnabled() bool { return EnvEnableTestRunAndExit.String() != "" } +const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~!@#$%^&*(){}`[]\\=/?+|-_;:" + +var seededRand *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano())) + +func generateRandomString(length int) string { + b := make([]byte, length) + for i := range b { + b[i] = charset[seededRand.Intn(len(charset))] + } + return string(b) +} + +func (cfg *Config) GetEncryptKey() []byte { + return []byte(EnvImixEncryptKey.String()) +} + // ConfigureHTTPServer enables the configuration of the Tavern HTTP server. The endpoint field will be // overwritten with Tavern's HTTP handler when Tavern is run. func ConfigureHTTPServerFromEnv(options ...func(*http.Server)) func(*Config) { From 48cbb7c8c9b6da71ec5f0640cf0b63edeeecef5e Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 18 Jun 2024 02:36:38 +0000 Subject: [PATCH 082/141] Update docs. --- docs/_docs/admin-guide/tavern.md | 6 ++++++ docs/_docs/user-guide/imix.md | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/docs/_docs/admin-guide/tavern.md b/docs/_docs/admin-guide/tavern.md index 16279f494..af715cfaa 100644 --- a/docs/_docs/admin-guide/tavern.md +++ b/docs/_docs/admin-guide/tavern.md @@ -104,6 +104,12 @@ Below are some deployment gotchas and notes that we try to address with Terrafor ## Configuration +### Application layer crypto + +Tavern recieves the encryption key for app layer crypto through an environment variable `IMIX_ENCRYPT_KEY`. This variable must be the same for agent builds and all running instances of Tavern. If the variable is not set Tavern will pick a random 64 character password. To retrieve the randomly set variable check the app logs + +`2024/06/18 02:35:53 [WARN] No value for 'IMIX_ENCRYPT_KEY' provided, defaulting to /1oIbH~L#urAr0s75A:+0WMF8V*2I-0Z4Q6d[j-SBDBk]s4FCS&x~NmsVYOO0G6x` + ### Metrics By default, Tavern does not export metrics. You may use the below environment configuration variables to enable [Prometheus](https://prometheus.io/docs/introduction/overview/) metric collection. These metrics become available at the "/metrics" endpoint configured. These metrics are hosted on a separate HTTP server such that it can be restricted to localhost (default). This is because the endpoint is unauthenticated, and would leak sensitive information if it was accessible. diff --git a/docs/_docs/user-guide/imix.md b/docs/_docs/user-guide/imix.md index c1a8c30df..e49911a8e 100644 --- a/docs/_docs/user-guide/imix.md +++ b/docs/_docs/user-guide/imix.md @@ -15,6 +15,7 @@ Imix has compile-time configuration, that may be specified using environment var | Env Var | Description | Default | Required | | ------- | ----------- | ------- | -------- | +| IMIX_ENCRYPT_KEY | Secret key to encrypt app layer crypto | - | Yes | | IMIX_CALLBACK_URI | URI for initial callbacks (must specify a scheme, e.g. `http://`) | `http://127.0.0.1:80` | No | | IMIX_CALLBACK_INTERVAL | Duration between callbacks, in seconds. | `5` | No | | IMIX_RETRY_INTERVAL | Duration to wait before restarting the agent loop if an error occurs, in seconds. | `5` | No | @@ -74,6 +75,9 @@ This isn't ideal as in the UI each new beacon will appear as thought it were on ## Static cross compilation +**We strongly recommend building agents inside the provided devcontainer `.devcontainer`** +Building in the dev container limits variables that might cause issues and is the most tested way to compile. + ### Linux ```bash @@ -82,6 +86,9 @@ rustup target add x86_64-unknown-linux-musl sudo apt update sudo apt install musl-tools cd realm/implants/imix/ + +IMIX_ENCRYPT_KEY=$(LC_ALL=C tr -dc '[:graph:]' Date: Tue, 18 Jun 2024 02:38:34 +0000 Subject: [PATCH 083/141] Fix tests? --- .github/workflows/tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1eb7d7208..f1f5e56ac 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -77,6 +77,8 @@ jobs: with: tool: nextest,cargo-llvm-cov - name: 🔎 Run tests + env: + IMIX_ENCRYPT_KEY: "cicd" run: | cd ./implants/ && cargo fmt --check && From 1ee4f42452196d39ede3368db6e0f469eb892dd2 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 17:31:07 +0000 Subject: [PATCH 084/141] Abort if key is not set. --- tavern/config.go | 15 +-------------- tavern/env.go | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/tavern/config.go b/tavern/config.go index 1aa571a6a..acababfac 100644 --- a/tavern/config.go +++ b/tavern/config.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "log" - "math/rand" "net/http" "strings" "time" @@ -74,7 +73,7 @@ var ( EnvEnableMetrics = EnvString{"ENABLE_METRICS", ""} // EnvImixEncryptKey is the secret key used to encrypt app layer communication - EnvImixEncryptKey = EnvString{"IMIX_ENCRYPT_KEY", generateRandomString(64)} + EnvImixEncryptKey = EnvRequiredString{"IMIX_ENCRYPT_KEY"} ) // Config holds information that controls the behaviour of Tavern @@ -198,18 +197,6 @@ func (cfg *Config) IsTestRunAndExitEnabled() bool { return EnvEnableTestRunAndExit.String() != "" } -const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~!@#$%^&*(){}`[]\\=/?+|-_;:" - -var seededRand *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano())) - -func generateRandomString(length int) string { - b := make([]byte, length) - for i := range b { - b[i] = charset[seededRand.Intn(len(charset))] - } - return string(b) -} - func (cfg *Config) GetEncryptKey() []byte { return []byte(EnvImixEncryptKey.String()) } diff --git a/tavern/env.go b/tavern/env.go index 80471e72e..7e9e3d9ea 100644 --- a/tavern/env.go +++ b/tavern/env.go @@ -6,6 +6,21 @@ import ( "strconv" ) +// EnvString represents a string that is configured using environment variables. +type EnvRequiredString struct { + Key string +} + +// String parsed from the environment variable. +func (env EnvRequiredString) String() string { + if val := os.Getenv(env.Key); val != "" { + return val + } else { + log.Printf("[ERROR] No value for required variable '%s' provided, Aborting.", env.Key) + panic("Missing variable") + } +} + // EnvString represents a string that is configured using environment variables. type EnvString struct { Key string From fcebdd6121ab68555ed252b332e851ed83704eab Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 17:54:30 +0000 Subject: [PATCH 085/141] static defaults are dangerous. --- docs/_docs/admin-guide/tavern.md | 11 +++++++++-- implants/lib/pb/src/xchacha.rs | 16 +++++++++++----- tavern/config.go | 14 +++++++++++++- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/docs/_docs/admin-guide/tavern.md b/docs/_docs/admin-guide/tavern.md index af715cfaa..cecf381f7 100644 --- a/docs/_docs/admin-guide/tavern.md +++ b/docs/_docs/admin-guide/tavern.md @@ -106,9 +106,16 @@ Below are some deployment gotchas and notes that we try to address with Terrafor ### Application layer crypto -Tavern recieves the encryption key for app layer crypto through an environment variable `IMIX_ENCRYPT_KEY`. This variable must be the same for agent builds and all running instances of Tavern. If the variable is not set Tavern will pick a random 64 character password. To retrieve the randomly set variable check the app logs +Tavern implements static key symmetric encryption using xchacha20-poly1305. -`2024/06/18 02:35:53 [WARN] No value for 'IMIX_ENCRYPT_KEY' provided, defaulting to /1oIbH~L#urAr0s75A:+0WMF8V*2I-0Z4Q6d[j-SBDBk]s4FCS&x~NmsVYOO0G6x` +Tavern recieves the encryption key for app layer crypto through an environment variable `IMIX_ENCRYPT_KEY`. This variable must be the same for agent builds and all running instances of Tavern. + +If the variable is not set Tavern and Imix will default to `I Don't care how small the room is I cast fireball`. This is a dangerous stop gap we've implemented while we build out the app layer crypto. Long term we're moving to asymmetric encryption and don't want to build a safe way to handle the shared key since it will be going away. For now implementers should not rely on the static key encryption or should take care to safely modify the key. + +The vaule is set in: + +* `realm/tavern/config.go`:`EnvImixEncryptKeyDefault` +* `realm/implants/lib/pb/src/xchacha.rs`:`IMIX_ENCRYPT_KEY_DEFAULT` ### Metrics diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index 21e5fe0f1..58b7e2bf4 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -17,15 +17,21 @@ pub struct ChaChaSvc { key: Vec, } -const IMIX_ENCRYPT_KEY: &str = env!( - "IMIX_ENCRYPT_KEY", - "Please set `IMIX_ENCRYPT_KEY` env variable" -); +// !!!! DANGER !!!!! +// This is the default static key set to ensure compatability between server and client +// in debug builds. This key must be changed in order to protect data. We're still in the +// process of implementing app layer crypto and this is temporary. Do not rely on the +// app layer crypto and ensure you're using proper TLS. +const IMIX_ENCRYPT_KEY_DEFAULT: &str = "I Don't care how small the room is I cast fireball"; +const IMIX_ENCRYPT_KEY: Option<&'static str> = option_env!("IMIX_ENCRYPT_KEY",); impl Default for ChaChaSvc { fn default() -> Self { Self { - key: IMIX_ENCRYPT_KEY.into(), + key: match IMIX_ENCRYPT_KEY { + Some(res) => res.into(), + None => IMIX_ENCRYPT_KEY_DEFAULT.into(), + }, } } } diff --git a/tavern/config.go b/tavern/config.go index acababfac..e0d6b3f05 100644 --- a/tavern/config.go +++ b/tavern/config.go @@ -20,6 +20,15 @@ import ( "realm.pub/tavern/tomes" ) +const REDACTED = "[REDACTED]" + +// !!!! DANGER !!!!! +// This is the default static key set to ensure compatability between server and client +// in debug builds. This key must be changed in order to protect data. We're still in the +// process of implementing app layer crypto and this is temporary. Do not rely on the +// app layer crypto and ensure you're using proper TLS. +const EnvImixEncryptKeyDefault = "I Don't care how small the room is I cast fireball" + var ( // EnvEnableTestData if set will populate the database with test data. // EnvEnableTestRunAndExit will start the application, but exit immediately after. @@ -73,7 +82,7 @@ var ( EnvEnableMetrics = EnvString{"ENABLE_METRICS", ""} // EnvImixEncryptKey is the secret key used to encrypt app layer communication - EnvImixEncryptKey = EnvRequiredString{"IMIX_ENCRYPT_KEY"} + EnvImixEncryptKey = EnvString{"IMIX_ENCRYPT_KEY", REDACTED} ) // Config holds information that controls the behaviour of Tavern @@ -198,6 +207,9 @@ func (cfg *Config) IsTestRunAndExitEnabled() bool { } func (cfg *Config) GetEncryptKey() []byte { + if EnvImixEncryptKey.String() == REDACTED { + return []byte(EnvImixEncryptKeyDefault) + } return []byte(EnvImixEncryptKey.String()) } From 8c08d2e007cc69ca30f09db331633b4dd8666024 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 17:56:29 +0000 Subject: [PATCH 086/141] Remove set key from cicd --- .github/workflows/tests.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f1f5e56ac..1eb7d7208 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -77,8 +77,6 @@ jobs: with: tool: nextest,cargo-llvm-cov - name: 🔎 Run tests - env: - IMIX_ENCRYPT_KEY: "cicd" run: | cd ./implants/ && cargo fmt --check && From 7d00809cd1c9cbcf3aac6e0c6342ae324a757072 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 17:59:03 +0000 Subject: [PATCH 087/141] Add var for encrypt key. --- terraform/main.tf | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/terraform/main.tf b/terraform/main.tf index 0ee9cfa21..8834db64e 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -88,6 +88,13 @@ variable "enable_metrics" { description = "Enable prometheus sidecar and Tavern metrics collection" default = false } +variable "imix_encrypt_key" { + type = string + description = "The encryption key tavern and imix should use to talk to each other" + sensitive = true + default = "" +} + provider "google" { project = var.gcp_project @@ -199,6 +206,10 @@ resource "google_cloud_run_service" "tavern" { name = "ENABLE_METRICS" value = var.enable_metrics ? "1" : "" } + env { + name = "IMIX_ENCRYPT_KEY" + value = var.imix_encrypt_key + } } // Only create prometheus sidecar if metrics enabled From d70d7d64419e2fb8fb3af155dd300409e7588447 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:02:21 +0000 Subject: [PATCH 088/141] Update terraform --- docs/_docs/admin-guide/tavern.md | 5 +++++ terraform/main.tf | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/_docs/admin-guide/tavern.md b/docs/_docs/admin-guide/tavern.md index cecf381f7..ff30a899a 100644 --- a/docs/_docs/admin-guide/tavern.md +++ b/docs/_docs/admin-guide/tavern.md @@ -116,6 +116,11 @@ The vaule is set in: * `realm/tavern/config.go`:`EnvImixEncryptKeyDefault` * `realm/implants/lib/pb/src/xchacha.rs`:`IMIX_ENCRYPT_KEY_DEFAULT` +* `realm/terraform/main.tf`:`imix_encrypt_key` + +| Env Var | Description | Default | Required | +| ------- | ----------- | ------- | -------- | +| IMIX_ENCRYPT_KEY | Define the encryption key for app layer crypto | "I Don't care how small the room is I cast fireball" | Yes | ### Metrics diff --git a/terraform/main.tf b/terraform/main.tf index 8834db64e..b9e813ee2 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -92,7 +92,7 @@ variable "imix_encrypt_key" { type = string description = "The encryption key tavern and imix should use to talk to each other" sensitive = true - default = "" + default = "I Don't care how small the room is I cast fireball" } From 052c5001ddb70de36638410e3bd9391d8019caec Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:06:49 +0000 Subject: [PATCH 089/141] Fix debug and errors. --- tavern/internal/cryptocodec/cryptocodec.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tavern/internal/cryptocodec/cryptocodec.go b/tavern/internal/cryptocodec/cryptocodec.go index 801d78854..e65a9094a 100644 --- a/tavern/internal/cryptocodec/cryptocodec.go +++ b/tavern/internal/cryptocodec/cryptocodec.go @@ -28,18 +28,14 @@ func NewStreamDecryptCodec() StreamDecryptCodec { } func (s StreamDecryptCodec) Marshal(v any) ([]byte, error) { - log.Println("Marshal") proto := encoding.GetCodec("proto") res, err := proto.Marshal(v) - log.Println("Marshal buf ", res) enc_res := s.Csvc.Encrypt(res) return enc_res, err } func (s StreamDecryptCodec) Unmarshal(buf []byte, v any) error { - log.Println("Decrypt:", buf) dec_buf := s.Csvc.Decrypt(buf) - log.Println("Unmarshal:", dec_buf) proto := encoding.GetCodec("proto") return proto.Unmarshal(dec_buf, v) } @@ -94,7 +90,8 @@ func (csvc *CryptoSvc) Decrypt(in_arr []byte) []byte { func (csvc *CryptoSvc) Encrypt(in_arr []byte) []byte { nonce := make([]byte, csvc.Aead.NonceSize(), csvc.Aead.NonceSize()+len(in_arr)+csvc.Aead.Overhead()) if _, err := rand.Read(nonce); err != nil { - panic(err) + fmt.Printf("Failed to encrypt %v\n", err) + return []byte{} } encryptedMsg := csvc.Aead.Seal(nonce, nonce, in_arr, nil) return encryptedMsg From 399421bf1f87d9ce5c741b7e17d2d4dea743ea15 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:08:48 +0000 Subject: [PATCH 090/141] Updating warnings. --- implants/lib/pb/src/xchacha.rs | 2 +- tavern/config.go | 2 +- terraform/main.tf | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index 58b7e2bf4..7eb51d889 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -21,7 +21,7 @@ pub struct ChaChaSvc { // This is the default static key set to ensure compatability between server and client // in debug builds. This key must be changed in order to protect data. We're still in the // process of implementing app layer crypto and this is temporary. Do not rely on the -// app layer crypto and ensure you're using proper TLS. +// app layer crypto without changing this default. const IMIX_ENCRYPT_KEY_DEFAULT: &str = "I Don't care how small the room is I cast fireball"; const IMIX_ENCRYPT_KEY: Option<&'static str> = option_env!("IMIX_ENCRYPT_KEY",); diff --git a/tavern/config.go b/tavern/config.go index e0d6b3f05..80df283dd 100644 --- a/tavern/config.go +++ b/tavern/config.go @@ -26,7 +26,7 @@ const REDACTED = "[REDACTED]" // This is the default static key set to ensure compatability between server and client // in debug builds. This key must be changed in order to protect data. We're still in the // process of implementing app layer crypto and this is temporary. Do not rely on the -// app layer crypto and ensure you're using proper TLS. +// app layer crypto without changing this default. const EnvImixEncryptKeyDefault = "I Don't care how small the room is I cast fireball" var ( diff --git a/terraform/main.tf b/terraform/main.tf index b9e813ee2..c740acfa1 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -88,6 +88,11 @@ variable "enable_metrics" { description = "Enable prometheus sidecar and Tavern metrics collection" default = false } +// !!!! DANGER !!!!! +// This is the default static key set to ensure compatability between server and client +// in debug builds. This key must be changed in order to protect data. We're still in the +// process of implementing app layer crypto and this is temporary. Do not rely on the +// app layer crypto without changing this default. variable "imix_encrypt_key" { type = string description = "The encryption key tavern and imix should use to talk to each other" From fe89969cf7cf794e10fc35d5d62c2dfd4c1ecdb0 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:10:17 +0000 Subject: [PATCH 091/141] Fix prints --- implants/lib/pb/src/xchacha.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index 7eb51d889..6ba50daf4 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -82,7 +82,8 @@ where fn encode(&mut self, item: Self::Item, buf: &mut EncodeBuf<'_>) -> Result<(), Self::Error> { if !buf.has_remaining_mut() { // Can't add to the buffer. - println!("DANGER can't add to the buffer."); + #[cfg(debug_assertions)] + log::debug!("DANGER can't add to the buffer."); } let key = self.1.key.as_slice(); @@ -95,13 +96,11 @@ where let pt_vec = item.encode_to_vec(); - println!("ENCODE DEC: {:?}", pt_vec); - // let _ = buf.writer().write_all(&pt_vec); - let ciphertext = match cipher.encrypt(&nonce, pt_vec.as_slice()) { Ok(ct) => ct, Err(err) => { - println!("err: {:?}", err); + #[cfg(debug_assertions)] + log::debug!("err: {:?}", err); return Err(Status::new(tonic::Code::Internal, err.to_string())); } }; @@ -109,8 +108,6 @@ where let _ = buf.writer().write_all(nonce.as_slice()); buf.writer().write_all(ciphertext.as_slice())?; - println!("ENCODE ENC: {:?}", buf); - Ok(()) } } @@ -136,7 +133,8 @@ where let bytes_read = match reader.read(&mut bytes_in) { Ok(n) => n, Err(err) => { - println!("err: {:?}", err); + #[cfg(debug_assertions)] + log::debug!("err: {:?}", err); return Err(Status::new(tonic::Code::Internal, err.to_string())); } }; @@ -154,7 +152,8 @@ where let plaintext = match cipher.decrypt(GenericArray::from_slice(nonce), ciphertext.as_ref()) { Ok(pt) => pt, Err(err) => { - println!("err: {:?}", err); + #[cfg(debug_assertions)] + log::debug!("err: {:?}", err); return Err(Status::new(tonic::Code::Internal, err.to_string())); } }; From 7860bac8402fa62aa096dea9ffafa5b95c091f49 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:12:25 +0000 Subject: [PATCH 092/141] Remove required string. --- tavern/env.go | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/tavern/env.go b/tavern/env.go index 7e9e3d9ea..80471e72e 100644 --- a/tavern/env.go +++ b/tavern/env.go @@ -6,21 +6,6 @@ import ( "strconv" ) -// EnvString represents a string that is configured using environment variables. -type EnvRequiredString struct { - Key string -} - -// String parsed from the environment variable. -func (env EnvRequiredString) String() string { - if val := os.Getenv(env.Key); val != "" { - return val - } else { - log.Printf("[ERROR] No value for required variable '%s' provided, Aborting.", env.Key) - panic("Missing variable") - } -} - // EnvString represents a string that is configured using environment variables. type EnvString struct { Key string From 9188434815ed7bb7cfbd9106653cdc00eeee7284 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:13:56 +0000 Subject: [PATCH 093/141] Revert example tome --- tavern/tomes/example/main.eldritch | 11 +---------- tavern/tomes/example/metadata.yml | 5 +++++ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/tavern/tomes/example/main.eldritch b/tavern/tomes/example/main.eldritch index aee9d8c0b..693ffb9ac 100644 --- a/tavern/tomes/example/main.eldritch +++ b/tavern/tomes/example/main.eldritch @@ -1,10 +1 @@ -assets.copy("example/linux/test-file", "/tmp/winnnnz") -print(file.read("/tmp/winnnnz")) -test_hash = crypto.hash_file("/tmp/winnnnz", "SHA256") -if not "30c2bf79fb57fe7c9bea00a2bfe0cb2e9b3ce0b694aa63c633a2bd44a5c87e56" == test_hash: - print("Hashes don't match!") - print(file.read("/tmp/winnnnz")) - -report.file("/etc/passwd") -print("Success! ✅") -file.remove("/tmp/winnnnz") +print(input_params['msg']) diff --git a/tavern/tomes/example/metadata.yml b/tavern/tomes/example/metadata.yml index 5b6704a33..ea86b7123 100644 --- a/tavern/tomes/example/metadata.yml +++ b/tavern/tomes/example/metadata.yml @@ -3,3 +3,8 @@ description: An example tome! author: kcarretto support_model: FIRST_PARTY tactic: UNSPECIFIED +paramdefs: +- label: Message + name: msg + placeholder: Something to print + type: string From dddc0c9821f67d9633ac8046c72cc8415e999e87 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:45:06 +0000 Subject: [PATCH 094/141] Remove todo --- tavern/internal/cryptocodec/cryptocodec.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/tavern/internal/cryptocodec/cryptocodec.go b/tavern/internal/cryptocodec/cryptocodec.go index e65a9094a..05ffb4b3d 100644 --- a/tavern/internal/cryptocodec/cryptocodec.go +++ b/tavern/internal/cryptocodec/cryptocodec.go @@ -17,8 +17,6 @@ func init() { encoding.RegisterCodec(StreamDecryptCodec{}) } -// TODO decyrpt and encrypt in place - type StreamDecryptCodec struct { Csvc CryptoSvc } From 96a9f9af526faa1ce4e615dbdb99ba4c329f1938 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:49:07 +0000 Subject: [PATCH 095/141] Remove deny_warnings --- implants/golem/src/lib.rs | 2 -- implants/golem/src/main.rs | 2 -- implants/imix/src/lib.rs | 2 -- implants/imix/src/main.rs | 1 - implants/lib/eldritch/src/lib.rs | 2 -- 5 files changed, 9 deletions(-) diff --git a/implants/golem/src/lib.rs b/implants/golem/src/lib.rs index 7ed0a3a55..537b47def 100644 --- a/implants/golem/src/lib.rs +++ b/implants/golem/src/lib.rs @@ -1,5 +1,3 @@ -#![deny(warnings)] - #[derive(Debug)] pub enum Error { Io(std::io::Error), diff --git a/implants/golem/src/main.rs b/implants/golem/src/main.rs index 8f6be18e1..df4c45c09 100644 --- a/implants/golem/src/main.rs +++ b/implants/golem/src/main.rs @@ -1,5 +1,3 @@ -#![deny(warnings)] - extern crate eldritch; extern crate golem; diff --git a/implants/imix/src/lib.rs b/implants/imix/src/lib.rs index 9de3c4e10..8b62e1fdb 100644 --- a/implants/imix/src/lib.rs +++ b/implants/imix/src/lib.rs @@ -1,5 +1,3 @@ -#![deny(warnings)] - pub mod agent; mod config; mod install; diff --git a/implants/imix/src/main.rs b/implants/imix/src/main.rs index 501e3c2a4..a15974510 100644 --- a/implants/imix/src/main.rs +++ b/implants/imix/src/main.rs @@ -1,5 +1,4 @@ #![windows_subsystem = "windows"] -#![deny(warnings)] #[cfg(all(feature = "win_service", windows))] #[macro_use] diff --git a/implants/lib/eldritch/src/lib.rs b/implants/lib/eldritch/src/lib.rs index e6a1c046b..b602966ae 100644 --- a/implants/lib/eldritch/src/lib.rs +++ b/implants/lib/eldritch/src/lib.rs @@ -1,5 +1,3 @@ -#![deny(warnings)] - pub mod assets; pub mod crypto; pub mod file; From a40e41253c4ab041d0b3a11f0f2ffb269585bd6a Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 21:38:03 +0000 Subject: [PATCH 096/141] Remove docs - not supported. --- docs/_docs/admin-guide/tavern.md | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/docs/_docs/admin-guide/tavern.md b/docs/_docs/admin-guide/tavern.md index ff30a899a..16279f494 100644 --- a/docs/_docs/admin-guide/tavern.md +++ b/docs/_docs/admin-guide/tavern.md @@ -104,24 +104,6 @@ Below are some deployment gotchas and notes that we try to address with Terrafor ## Configuration -### Application layer crypto - -Tavern implements static key symmetric encryption using xchacha20-poly1305. - -Tavern recieves the encryption key for app layer crypto through an environment variable `IMIX_ENCRYPT_KEY`. This variable must be the same for agent builds and all running instances of Tavern. - -If the variable is not set Tavern and Imix will default to `I Don't care how small the room is I cast fireball`. This is a dangerous stop gap we've implemented while we build out the app layer crypto. Long term we're moving to asymmetric encryption and don't want to build a safe way to handle the shared key since it will be going away. For now implementers should not rely on the static key encryption or should take care to safely modify the key. - -The vaule is set in: - -* `realm/tavern/config.go`:`EnvImixEncryptKeyDefault` -* `realm/implants/lib/pb/src/xchacha.rs`:`IMIX_ENCRYPT_KEY_DEFAULT` -* `realm/terraform/main.tf`:`imix_encrypt_key` - -| Env Var | Description | Default | Required | -| ------- | ----------- | ------- | -------- | -| IMIX_ENCRYPT_KEY | Define the encryption key for app layer crypto | "I Don't care how small the room is I cast fireball" | Yes | - ### Metrics By default, Tavern does not export metrics. You may use the below environment configuration variables to enable [Prometheus](https://prometheus.io/docs/introduction/overview/) metric collection. These metrics become available at the "/metrics" endpoint configured. These metrics are hosted on a separate HTTP server such that it can be restricted to localhost (default). This is because the endpoint is unauthenticated, and would leak sensitive information if it was accessible. From e5ff8a32e793254b9e9efc263b299f4e8d78ace1 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 19 Jun 2024 21:51:21 +0000 Subject: [PATCH 097/141] No docs --- docs/_docs/user-guide/imix.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docs/_docs/user-guide/imix.md b/docs/_docs/user-guide/imix.md index e49911a8e..6159b0c5f 100644 --- a/docs/_docs/user-guide/imix.md +++ b/docs/_docs/user-guide/imix.md @@ -15,7 +15,6 @@ Imix has compile-time configuration, that may be specified using environment var | Env Var | Description | Default | Required | | ------- | ----------- | ------- | -------- | -| IMIX_ENCRYPT_KEY | Secret key to encrypt app layer crypto | - | Yes | | IMIX_CALLBACK_URI | URI for initial callbacks (must specify a scheme, e.g. `http://`) | `http://127.0.0.1:80` | No | | IMIX_CALLBACK_INTERVAL | Duration between callbacks, in seconds. | `5` | No | | IMIX_RETRY_INTERVAL | Duration to wait before restarting the agent loop if an error occurs, in seconds. | `5` | No | @@ -87,8 +86,6 @@ sudo apt update sudo apt install musl-tools cd realm/implants/imix/ -IMIX_ENCRYPT_KEY=$(LC_ALL=C tr -dc '[:graph:]' Date: Wed, 19 Jun 2024 22:00:11 +0000 Subject: [PATCH 098/141] Revert "Remove deny_warnings" This reverts commit fbf83b1f0456e8cfdf9339f35ebb7f0f66cfb8ed. --- implants/golem/src/lib.rs | 2 ++ implants/golem/src/main.rs | 2 ++ implants/imix/src/lib.rs | 2 ++ implants/imix/src/main.rs | 1 + implants/lib/eldritch/src/lib.rs | 2 ++ 5 files changed, 9 insertions(+) diff --git a/implants/golem/src/lib.rs b/implants/golem/src/lib.rs index 537b47def..7ed0a3a55 100644 --- a/implants/golem/src/lib.rs +++ b/implants/golem/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(warnings)] + #[derive(Debug)] pub enum Error { Io(std::io::Error), diff --git a/implants/golem/src/main.rs b/implants/golem/src/main.rs index df4c45c09..8f6be18e1 100644 --- a/implants/golem/src/main.rs +++ b/implants/golem/src/main.rs @@ -1,3 +1,5 @@ +#![deny(warnings)] + extern crate eldritch; extern crate golem; diff --git a/implants/imix/src/lib.rs b/implants/imix/src/lib.rs index 8b62e1fdb..9de3c4e10 100644 --- a/implants/imix/src/lib.rs +++ b/implants/imix/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(warnings)] + pub mod agent; mod config; mod install; diff --git a/implants/imix/src/main.rs b/implants/imix/src/main.rs index a15974510..501e3c2a4 100644 --- a/implants/imix/src/main.rs +++ b/implants/imix/src/main.rs @@ -1,4 +1,5 @@ #![windows_subsystem = "windows"] +#![deny(warnings)] #[cfg(all(feature = "win_service", windows))] #[macro_use] diff --git a/implants/lib/eldritch/src/lib.rs b/implants/lib/eldritch/src/lib.rs index b602966ae..e6a1c046b 100644 --- a/implants/lib/eldritch/src/lib.rs +++ b/implants/lib/eldritch/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(warnings)] + pub mod assets; pub mod crypto; pub mod file; From 3784c67a66f46fd5991a1b180da7d6115fd84053 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Sat, 29 Jun 2024 18:34:18 -0500 Subject: [PATCH 099/141] App layer crypto codec asym (#784) * Rough POC * Update key * Debug * Works on my computer. * Claenup * Unused edps --- implants/Cargo.toml | 2 + implants/lib/pb/Cargo.toml | 6 +- implants/lib/pb/src/xchacha.rs | 124 +++++++++++----- tavern/app.go | 29 +++- tavern/internal/cryptocodec/cryptocodec.go | 163 +++++++++++++++++---- 5 files changed, 254 insertions(+), 70 deletions(-) diff --git a/implants/Cargo.toml b/implants/Cargo.toml index 3d94bc20a..ff7eca584 100644 --- a/implants/Cargo.toml +++ b/implants/Cargo.toml @@ -17,6 +17,7 @@ async-recursion = "1.0.0" async-trait = "0.1.68" base64 = "0.21.4" chrono = "0.4.34" +const-decoder = "0.3.0" clap = "3.2.23" default-net = "0.13.1" derive_more = "=0.99.17" @@ -84,6 +85,7 @@ windows-sys = "0.45.0" winreg = "0.51.0" chacha20poly1305 = "0.10.1" bytes = "1.6.0" +x25519-dalek = "2.0.1" [profile.release] diff --git a/implants/lib/pb/Cargo.toml b/implants/lib/pb/Cargo.toml index 00f0264d7..3ceae01b3 100644 --- a/implants/lib/pb/Cargo.toml +++ b/implants/lib/pb/Cargo.toml @@ -4,16 +4,20 @@ version = "0.0.5" edition = "2021" [dependencies] +anyhow = { workspace = true } log = { workspace = true } prost = { workspace = true } prost-types = { workspace = true } +rand_chacha = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } tokio-stream = { workspace = true } tonic = { workspace = true, features = ["tls-roots"] } +const-decoder = { workspace = true } chacha20poly1305 = { workspace = true } bytes = { workspace = true } -sha2 = { workspace = true } rand = { workspace = true } +x25519-dalek = { workspace = true } + [build-dependencies] tonic-build = { workspace = true, features = ["prost"] } diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index 6ba50daf4..d470fbebf 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -1,38 +1,53 @@ +use anyhow::{Context, Result}; use bytes::{Buf, BufMut}; use chacha20poly1305::{aead::generic_array::GenericArray, aead::Aead, AeadCore, KeyInit}; +use const_decoder::Decoder as const_decode; use prost::Message; use rand::rngs::OsRng; -use sha2::{Digest, Sha256}; +use rand_chacha::rand_core::SeedableRng; use std::{ + collections::HashMap, io::{Read, Write}, marker::PhantomData, + sync::{Mutex, OnceLock}, }; use tonic::{ codec::{Codec, DecodeBuf, Decoder, EncodeBuf, Encoder}, Status, }; +use x25519_dalek::{EphemeralSecret, PublicKey}; -#[derive(Debug, Clone)] -pub struct ChaChaSvc { - key: Vec, +const SERVER_PUBKEY_STR: &str = env!("SERVER_PUBKEY"); +const SERVER_PUBKEY: [u8; 32] = const_decode::Base64.decode(SERVER_PUBKEY_STR.as_bytes()); + +// ------------ + +fn key_history() -> &'static Mutex> { + static ARRAY: OnceLock>> = OnceLock::new(); + ARRAY.get_or_init(|| Mutex::new(HashMap::new())) +} + +fn add_key_history(pub_key: [u8; 32], shared_secret: [u8; 32]) { + key_history().lock().unwrap().insert(pub_key, shared_secret); // Mutex's must unwrap } -// !!!! DANGER !!!!! -// This is the default static key set to ensure compatability between server and client -// in debug builds. This key must be changed in order to protect data. We're still in the -// process of implementing app layer crypto and this is temporary. Do not rely on the -// app layer crypto without changing this default. -const IMIX_ENCRYPT_KEY_DEFAULT: &str = "I Don't care how small the room is I cast fireball"; -const IMIX_ENCRYPT_KEY: Option<&'static str> = option_env!("IMIX_ENCRYPT_KEY",); +fn get_key(pub_key: [u8; 32]) -> Result<[u8; 32]> { + let res = *key_history() + .lock() + .unwrap() // Mutex's must unwrap + .get(&pub_key) + .context("Key not found")?; + Ok(res) +} + +// ------------ + +#[derive(Debug, Clone)] +pub struct ChaChaSvc {} impl Default for ChaChaSvc { fn default() -> Self { - Self { - key: match IMIX_ENCRYPT_KEY { - Some(res) => res.into(), - None => IMIX_ENCRYPT_KEY_DEFAULT.into(), - }, - } + Self {} } } @@ -86,16 +101,26 @@ where log::debug!("DANGER can't add to the buffer."); } - let key = self.1.key.as_slice(); - let mut hasher = Sha256::new(); - hasher.update(key); - let key_hash = hasher.finalize(); + // Store server pubkey + let server_public = PublicKey::from(SERVER_PUBKEY); - let cipher = chacha20poly1305::XChaCha20Poly1305::new(GenericArray::from_slice(&key_hash)); + // Generate ephemeral keys + let rng = rand_chacha::ChaCha20Rng::from_entropy(); + let client_secret = EphemeralSecret::random_from_rng(rng); + let client_public = PublicKey::from(&client_secret); + + // Generate shared secret + let shared_secret = client_secret.diffie_hellman(&server_public); + add_key_history(*client_public.as_bytes(), *shared_secret.as_bytes()); + + // Generate nonce + let cipher = chacha20poly1305::XChaCha20Poly1305::new(GenericArray::from_slice( + shared_secret.as_bytes(), + )); let nonce = chacha20poly1305::XChaCha20Poly1305::generate_nonce(&mut OsRng); + // Encrypt data let pt_vec = item.encode_to_vec(); - let ciphertext = match cipher.encrypt(&nonce, pt_vec.as_slice()) { Ok(ct) => ct, Err(err) => { @@ -105,7 +130,9 @@ where } }; - let _ = buf.writer().write_all(nonce.as_slice()); + // Write pubkey + nonce + cipher text + buf.writer().write_all(client_public.as_bytes()); + buf.writer().write_all(nonce.as_slice()); buf.writer().write_all(ciphertext.as_slice())?; Ok(()) @@ -128,6 +155,7 @@ where type Error = Status; fn decode(&mut self, buf: &mut DecodeBuf<'_>) -> Result, Self::Error> { + // public key + xchacha nonce + ciphertext let mut reader = buf.reader(); let mut bytes_in = vec![0; DEFAULT_CODEC_BUFFER_SIZE]; let bytes_read = match reader.read(&mut bytes_in) { @@ -139,25 +167,47 @@ where } }; - let ciphertext = &bytes_in[0..bytes_read]; - let nonce = &ciphertext[0..24]; - let ciphertext = &ciphertext[24..]; - - let key = self.1.key.as_slice(); - let mut hasher = Sha256::new(); - hasher.update(key); - let key_hash = hasher.finalize(); - let cipher = chacha20poly1305::XChaCha20Poly1305::new(GenericArray::from_slice(&key_hash)); - + // TODO validate buffer size to avoid index out of bounds accesses + let buf = bytes_in + .get(0..bytes_read) + .context("Bytes read doesn't match buffer size") + .map_err(from_anyhow_error)?; + + let client_public = buf + .get(0..32) + .context("Input buffer doesn't have enough bytes for public key") + .map_err(from_anyhow_error)?; + + let nonce = buf + .get(32..56) + .context("Input buffer doesn't have enough bytes for nonce") + .map_err(from_anyhow_error)?; + + let ciphertext = buf + .get(56..) + .context("Input buffer doesn't have enough bytes for ciphertext") + .map_err(from_anyhow_error)?; + + // Get private key based on messages public key + let tmp_client_public_bytes = client_public.to_vec(); + let client_public_bytes = tmp_client_public_bytes.try_into().unwrap(); // Bruh idk how to not unwrap this :sob: + + let client_private_bytes = get_key(client_public_bytes).map_err(from_anyhow_error)?; + let cipher = chacha20poly1305::XChaCha20Poly1305::new(GenericArray::from_slice( + &client_private_bytes, + )); + + // Decrypt message let plaintext = match cipher.decrypt(GenericArray::from_slice(nonce), ciphertext.as_ref()) { Ok(pt) => pt, Err(err) => { #[cfg(debug_assertions)] - log::debug!("err: {:?}", err); + log::debug!("Error decrypting response: {:?}", err); return Err(Status::new(tonic::Code::Internal, err.to_string())); } }; + // Serialize let item = Message::decode(bytes::Bytes::from(plaintext)) .map(Option::Some) .map_err(from_decode_error)?; @@ -166,6 +216,10 @@ where } } +fn from_anyhow_error(error: anyhow::Error) -> Status { + Status::new(tonic::Code::Internal, error.to_string()) +} + fn from_decode_error(error: prost::DecodeError) -> Status { // Map Protobuf parse errors to an INTERNAL status code, as per // https://github.com/grpc/grpc/blob/master/doc/statuscodes.md diff --git a/tavern/app.go b/tavern/app.go index 1ed5c3bc3..687f803cd 100644 --- a/tavern/app.go +++ b/tavern/app.go @@ -2,8 +2,10 @@ package main import ( "context" + "crypto/ecdh" "crypto/ed25519" "crypto/rand" + "encoding/base64" "encoding/json" "fmt" "log" @@ -195,7 +197,7 @@ func NewServer(ctx context.Context, options ...func(*Config)) (*Server, error) { AllowUnactivated: true, }, "/c2.C2/": tavernhttp.Endpoint{ - Handler: newGRPCHandler(client, grpcShellMux, cfg.GetEncryptKey()), + Handler: newGRPCHandler(client, grpcShellMux), AllowUnauthenticated: true, AllowUnactivated: true, }, @@ -287,7 +289,7 @@ func newGraphQLHandler(client *ent.Client, repoImporter graphql.RepoImporter) ht oc := gqlgraphql.GetOperationContext(ctx) reqVars, err := json.Marshal(oc.Variables) if err != nil { - gqlLogger.Printf("[ERROR] failed to marshal variables to JSON: %v", err) + gqlLogger.Printf("[ERROR] failed to marshal variables to JSON: %v\n", err) return next(ctx) } @@ -308,10 +310,29 @@ func newGraphQLHandler(client *ent.Client, repoImporter graphql.RepoImporter) ht }) } -func newGRPCHandler(client *ent.Client, grpcShellMux *stream.Mux, crypto_key []byte) http.Handler { +func generate_key_pair() (*ecdh.PublicKey, *ecdh.PrivateKey) { + x22519 := ecdh.X25519() + priv_key, err := x22519.GenerateKey(rand.Reader) + if err != nil { + log.Printf("[ERROR] Failed to generate private key: %v\n", err) + panic("[ERROR] Failed to generate private key") + } + public_key, err := x22519.NewPublicKey(priv_key.PublicKey().Bytes()) + if err != nil { + log.Printf("[ERROR] Failed to generate public key: %v\n", err) + panic("[ERROR] Failed to generate public key") + } + + return public_key, priv_key +} + +func newGRPCHandler(client *ent.Client, grpcShellMux *stream.Mux) http.Handler { + public_key, priv_key := generate_key_pair() + log.Println("[INFO] Public key: ", base64.StdEncoding.EncodeToString(public_key.Bytes())) + log.Println("[INFO] Private key: ", base64.StdEncoding.EncodeToString(priv_key.Bytes())) c2srv := c2.New(client, grpcShellMux) xchacha := cryptocodec.StreamDecryptCodec{ - Csvc: cryptocodec.NewCryptoSvc(crypto_key), + Csvc: cryptocodec.NewCryptoSvc(priv_key), } grpcSrv := grpc.NewServer( grpc.ForceServerCodec(xchacha), diff --git a/tavern/internal/cryptocodec/cryptocodec.go b/tavern/internal/cryptocodec/cryptocodec.go index 05ffb4b3d..d09fb21db 100644 --- a/tavern/internal/cryptocodec/cryptocodec.go +++ b/tavern/internal/cryptocodec/cryptocodec.go @@ -1,19 +1,29 @@ package cryptocodec import ( - "crypto/cipher" + "bytes" + "crypto/ecdh" "crypto/rand" - "crypto/sha256" + "errors" "fmt" "log" + "runtime" + "strconv" + "sync" + "github.com/cloudflare/circl/dh/x25519" "golang.org/x/crypto/chacha20poly1305" "google.golang.org/grpc/encoding" ) +// TODO: Switch to a gomap and mutex. +var session_pub_keys = sync.Map{} + +// TODO: Should we make this a random long byte array in case it gets used anywhere to avoid encrypting data with a week key? - Sliver handles errors in this way. +var FAILURE_BYTES = []byte{} + func init() { - log.Println("Loading xchacha20-poly1305") - // Probably want to use the `ForceServerCodec` option instead. + log.Println("[INFO] Loading xchacha20-poly1305") encoding.RegisterCodec(StreamDecryptCodec{}) } @@ -26,6 +36,11 @@ func NewStreamDecryptCodec() StreamDecryptCodec { } func (s StreamDecryptCodec) Marshal(v any) ([]byte, error) { + id, err := goid() + if err != nil { + log.Println("[ERROR] Unable to find GOID ", id) + return FAILURE_BYTES, err + } proto := encoding.GetCodec("proto") res, err := proto.Marshal(v) enc_res := s.Csvc.Encrypt(res) @@ -33,7 +48,13 @@ func (s StreamDecryptCodec) Marshal(v any) ([]byte, error) { } func (s StreamDecryptCodec) Unmarshal(buf []byte, v any) error { - dec_buf := s.Csvc.Decrypt(buf) + id, err := goid() + if err != nil { + log.Println("[ERROR] Unable to find GOID ", id) + return err + } + dec_buf, pub_key := s.Csvc.Decrypt(buf) + s.Csvc.SetAgentPubkey(pub_key) proto := encoding.GetCodec("proto") return proto.Unmarshal(dec_buf, v) } @@ -43,54 +64,136 @@ func (s StreamDecryptCodec) Name() string { } type CryptoSvc struct { - Aead cipher.AEAD + // Aead cipher.AEAD + priv_key *ecdh.PrivateKey } -func NewCryptoSvc(key []byte) CryptoSvc { - hasher := sha256.New() - hasher.Write(key) - key = hasher.Sum(nil) - aead, err := chacha20poly1305.NewX(key) +func NewCryptoSvc(priv_key *ecdh.PrivateKey) CryptoSvc { + return CryptoSvc{ + priv_key: priv_key, + } +} +func (csvc *CryptoSvc) GetAgentPubkey() []byte { + id, err := goid() if err != nil { - panic(err) + log.Println("[ERROR] Unable to find GOID ", id) + return FAILURE_BYTES + } + res, ok := session_pub_keys.Load(id) + if !ok { + log.Println("[ERROR] Public key not found") } + return res.([]byte) +} - nonce := make([]byte, aead.NonceSize()) - if _, err := rand.Read(nonce); err != nil { - panic(err) +func (csvc *CryptoSvc) SetAgentPubkey(client_pub_key []byte) { + id, err := goid() + if err != nil { + log.Println("[ERROR] Failed to get goid") } + session_pub_keys.Store(id, client_pub_key) +} - res := CryptoSvc{ - Aead: aead, +func (csvc *CryptoSvc) generate_shared_key(client_pub_key_bytes []byte) []byte { + fmt.Println("[DEBUG] client_pub_key_bytes: ", client_pub_key_bytes) + x22519_curve := ecdh.X25519() + client_pub_key, err := x22519_curve.NewPublicKey(client_pub_key_bytes) + if err != nil { + log.Printf("[ERROR] Failed to create public key %v", err) + return FAILURE_BYTES } - return res + shared_key, err := csvc.priv_key.ECDH(client_pub_key) + if err != nil { + log.Printf("[ERROR] Failed to get shared secret %v", err) + return FAILURE_BYTES + } + return shared_key } -func (csvc *CryptoSvc) Decrypt(in_arr []byte) []byte { - if len(in_arr) < csvc.Aead.NonceSize() { - fmt.Printf("Input bytes to short %d expected %d\n", len(in_arr), csvc.Aead.NonceSize()) - return []byte{} +func (csvc *CryptoSvc) Decrypt(in_arr []byte) ([]byte, []byte) { + // Read in pub key + if len(in_arr) < x25519.Size { + fmt.Printf("Input bytes to short %d expected at least %d\n", len(in_arr), x25519.Size) + return FAILURE_BYTES, FAILURE_BYTES + } + + client_pub_key_bytes := in_arr[:x25519.Size] + csvc.SetAgentPubkey(client_pub_key_bytes) + + // Generate shared secret + derived_key := csvc.generate_shared_key(client_pub_key_bytes) + + log.Println("[DEBUG] derived_key: ", derived_key) + aead, err := chacha20poly1305.NewX(derived_key) + if err != nil { + log.Printf("[ERROR] Failed to create xchacha key %v", err) + return FAILURE_BYTES, FAILURE_BYTES } - nonce, ciphertext := in_arr[:csvc.Aead.NonceSize()], in_arr[csvc.Aead.NonceSize():] - plaintext, err := csvc.Aead.Open(nil, nonce, ciphertext, nil) + // Progress in_arr buf + in_arr = in_arr[x25519.Size:] + + // Read nonce + if len(in_arr) < aead.NonceSize() { + fmt.Printf("Input bytes to short %d expected at least %d\n", len(in_arr), aead.NonceSize()) + return FAILURE_BYTES, FAILURE_BYTES + } + nonce, ciphertext := in_arr[:aead.NonceSize()], in_arr[aead.NonceSize():] + + // Decrypt + plaintext, err := aead.Open(nil, nonce, ciphertext, nil) if err != nil { fmt.Printf("Failed to decrypt %v\n", err) - return []byte{} + return FAILURE_BYTES, FAILURE_BYTES } - return plaintext + return plaintext, client_pub_key_bytes } +// TODO: Don't use [] ref. func (csvc *CryptoSvc) Encrypt(in_arr []byte) []byte { - nonce := make([]byte, csvc.Aead.NonceSize(), csvc.Aead.NonceSize()+len(in_arr)+csvc.Aead.Overhead()) + // Get the client pub key? + client_pub_key_bytes := csvc.GetAgentPubkey() + fmt.Println("[DEBUG] Got pub key: ", client_pub_key_bytes) + + // Generate shared secret + shared_key := csvc.generate_shared_key(client_pub_key_bytes) + aead, err := chacha20poly1305.NewX(shared_key) + if err != nil { + log.Printf("[ERROR] Failed to create xchacha key %v", err) + return FAILURE_BYTES + } + + nonce := make([]byte, aead.NonceSize(), aead.NonceSize()+len(in_arr)+aead.Overhead()) if _, err := rand.Read(nonce); err != nil { fmt.Printf("Failed to encrypt %v\n", err) - return []byte{} + return FAILURE_BYTES + } + encryptedMsg := aead.Seal(nonce, nonce, in_arr, nil) + return append(client_pub_key_bytes, encryptedMsg...) +} + +// TODO: Find a better way +// This is terrible, slow, and should never be used. +func goid() (int, error) { + buf := make([]byte, 32) + n := runtime.Stack(buf, false) + buf = buf[:n] + // goroutine 1 [running]: ... + var goroutinePrefix = []byte("goroutine ") + var errBadStack = errors.New("invalid runtime.Stack output") + buf, ok := bytes.CutPrefix(buf, goroutinePrefix) + if !ok { + return 0, errBadStack + } + + i := bytes.IndexByte(buf, ' ') + if i < 0 { + return 0, errBadStack } - encryptedMsg := csvc.Aead.Seal(nonce, nonce, in_arr, nil) - return encryptedMsg + + return strconv.Atoi(string(buf[:i])) } From 8752c9de7a0a9d509061ed9cf0d743c386f7fbb7 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 1 Jul 2024 00:50:01 +0000 Subject: [PATCH 100/141] Debug file secrets manager --- tavern/internal/secrets/debug_file.go | 178 +++++++++++++++++++++ tavern/internal/secrets/debug_file_test.go | 93 +++++++++++ tavern/internal/secrets/secrets.go | 7 + 3 files changed, 278 insertions(+) create mode 100644 tavern/internal/secrets/debug_file.go create mode 100644 tavern/internal/secrets/debug_file_test.go create mode 100644 tavern/internal/secrets/secrets.go diff --git a/tavern/internal/secrets/debug_file.go b/tavern/internal/secrets/debug_file.go new file mode 100644 index 000000000..04aee10fd --- /dev/null +++ b/tavern/internal/secrets/debug_file.go @@ -0,0 +1,178 @@ +package secrets + +import ( + "errors" + "fmt" + "log" + "os" + + "gopkg.in/yaml.v3" +) + +const DEFAULT_PERMS = 0644 +const DELIMITER = "=" +const MEGABYTES = 1000000 +const MAX_FILE_SIZE = 128 * MEGABYTES + +type Secret struct { + Key string + Value string +} + +type Secrets struct { + Secrets []Secret +} + +type DebugFileSecrets struct { + Name string + Path string +} + +func NewDebugFileSecrets(path string) SecretsManager { + return DebugFileSecrets{ + Name: "DebugFileSecrets", + Path: path, + } +} + +func (s DebugFileSecrets) GetName() string { + return s.Name +} + +func (s DebugFileSecrets) SetValue(key string, value string) (string, error) { + path, err := s.createSecretsFile() + if err != nil { + log.Printf("[ERROR] Failed to create secrets file %s: %v", path, err) + return "", err + } + + secrets, err := s.getYamlStruct(path) + if err != nil { + log.Printf("[ERROR] Failed to parse YAML file %s: %v", path, err) + return "", err + } + + var old_value string = "" + + // If the value exists update it + for idx, k := range secrets.Secrets { + if k.Key == key { + secrets.Secrets[idx].Value = value + old_value = k.Value + } + } + + // If the value doesn't exist create it + if old_value == "" { + secrets.Secrets = append( + secrets.Secrets, + Secret{ + Key: key, + Value: value, + }, + ) + } + + err = s.setYamlStruct(path, secrets) + if err != nil { + log.Printf("[ERROR] Failed to update YAML file %s: %v", path, err) + return "", err + } + + return old_value, nil +} + +func (s DebugFileSecrets) GetValue(key string) (string, error) { + path := s.Path + + secrets, err := s.getYamlStruct(path) + if err != nil { + log.Printf("[ERROR] Failed to parse YAML file %s: %v", path, err) + return "", err + } + + for _, k := range secrets.Secrets { + if k.Key == key { + return k.Value, nil + } + } + + return "", nil +} + +func (s DebugFileSecrets) setYamlStruct(path string, secrets Secrets) error { + data, err := yaml.Marshal(secrets) + if err != nil { + fmt.Printf("[ERROR] Failed to parse file YAML %s: %v", path, err) + return err + } + + file, err := os.OpenFile(path, os.O_RDWR, DEFAULT_PERMS) + if err != nil { + log.Printf("[ERROR] Failed to open secrets file %s: %v", path, err) + return err + } + + log.Printf("data: %s\n", data) + + _, err = file.Write(data) + if err != nil { + log.Printf("[ERROR] Failed to read file %s: %v", path, err) + return err + } + + return nil +} + +func (s DebugFileSecrets) getYamlStruct(path string) (Secrets, error) { + file, err := os.OpenFile(path, os.O_RDWR, DEFAULT_PERMS) + if err != nil { + log.Printf("[ERROR] Failed to open secrets file %s: %v", path, err) + return Secrets{}, err + } + + data := make([]byte, MAX_FILE_SIZE) + n, err := file.Read(data) + if err != nil { + log.Printf("[ERROR] Failed to read file %s: %v", path, err) + return Secrets{}, err + } + + data = data[0:n] + + var secrets Secrets + err = yaml.Unmarshal(data, &secrets) + if err != nil { + fmt.Printf("[ERROR] Failed to parse file YAML %s: %v", path, err) + return Secrets{}, err + } + + return secrets, nil +} + +func (s DebugFileSecrets) createSecretsFile() (string, error) { + _, err := os.Stat(s.Path) + if errors.Is(err, os.ErrNotExist) { + // Create file + f, err := os.OpenFile(s.Path, os.O_CREATE, DEFAULT_PERMS) + if err != nil { + log.Printf("[ERROR] Failed to create file %s\n", s.Path) + return s.Path, err + } + defer f.Close() + + // Write empty struct to file + err = s.setYamlStruct(s.Path, Secrets{}) + if err != nil { + log.Printf("[ERROR] Failed to set yaml struct") + return s.Path, err + } + } + return s.Path, nil +} + +// func checkFileExists(filePath string) bool { +// _, error := os.Stat(filePath) +// //return !os.IsNotExist(err) +// return !errors.Is(error, os.ErrNotExist) +// } diff --git a/tavern/internal/secrets/debug_file_test.go b/tavern/internal/secrets/debug_file_test.go new file mode 100644 index 000000000..eb7d4d74d --- /dev/null +++ b/tavern/internal/secrets/debug_file_test.go @@ -0,0 +1,93 @@ +package secrets_test + +import ( + "log" + "os" + "path" + "testing" + + "github.com/stretchr/testify/assert" + "realm.pub/tavern/internal/secrets" +) + +func createTestSecrets(t *testing.T) string { + // TODO: How do I clean up this test file 🫠 + tmpDir := t.TempDir() + secretsPath := path.Join(tmpDir, "secrets.yaml") + data := []byte(` +secrets: + - key: TAVERN_PRIVATE_KEY + value: Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE= + - key: super_secret_test_data + value: hello world! +`) + err := os.WriteFile(secretsPath, data, 0644) + if err != nil { + log.Fatalf("Failed to write test file %s: %v", secretsPath, err) + } + + return secretsPath +} + +func TestGetSecrets(t *testing.T) { + path := createTestSecrets(t) + defer os.Remove(path) + + secretsManager := secrets.NewDebugFileSecrets(path) + res, err := secretsManager.GetValue("super_secret_test_data") + assert.Nil(t, err) + assert.Equal(t, "hello world!", res) + + res, err = secretsManager.GetValue("TAVERN_PRIVATE_KEY") + assert.Nil(t, err) + assert.Equal(t, "Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE=", res) +} + +func TestSetSecretsAdd(t *testing.T) { + path := createTestSecrets(t) + defer os.Remove(path) + + secretsManager := secrets.NewDebugFileSecrets(path) + res, err := secretsManager.SetValue("WOAH!", "This works!") + assert.Nil(t, err) + assert.Equal(t, "", res) + + res, err = secretsManager.GetValue("WOAH!") + assert.Nil(t, err) + assert.Equal(t, "This works!", res) + + // --- + + res, err = secretsManager.SetValue("WOAH!", "This works too!") + assert.Nil(t, err) + assert.Equal(t, "This works!", res) + + res, err = secretsManager.GetValue("WOAH!") + assert.Nil(t, err) + assert.Equal(t, "This works too!", res) + + // --- + + res, err = secretsManager.GetValue("TAVERN_PRIVATE_KEY") + assert.Nil(t, err) + assert.Equal(t, "Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE=", res) +} + +func TestSetSecretsNew(t *testing.T) { + tmpDir := t.TempDir() + path := path.Join(tmpDir, "secrets.yaml") + defer os.Remove(path) + + secretsManager := secrets.NewDebugFileSecrets(path) + res, err := secretsManager.GetValue("super_secret_test_data") + // Make sure this fails + assert.NotNil(t, err) + + res, err = secretsManager.SetValue("super_secret_test_data", "now this will work") + assert.Nil(t, err) + assert.Equal(t, "", res) + + res, err = secretsManager.GetValue("super_secret_test_data") + assert.Nil(t, err) + assert.Equal(t, "now this will work", res) +} diff --git a/tavern/internal/secrets/secrets.go b/tavern/internal/secrets/secrets.go new file mode 100644 index 000000000..99c765aed --- /dev/null +++ b/tavern/internal/secrets/secrets.go @@ -0,0 +1,7 @@ +package secrets + +type SecretsManager interface { + GetName() string + SetValue(string, string) (string, error) + GetValue(string) (string, error) +} From 9fa3028d886637d78c8535a3fe98a808c330043f Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 1 Jul 2024 00:55:44 +0000 Subject: [PATCH 101/141] Remove static key --- tavern/config.go | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/tavern/config.go b/tavern/config.go index 80df283dd..c01ca4db2 100644 --- a/tavern/config.go +++ b/tavern/config.go @@ -22,13 +22,6 @@ import ( const REDACTED = "[REDACTED]" -// !!!! DANGER !!!!! -// This is the default static key set to ensure compatability between server and client -// in debug builds. This key must be changed in order to protect data. We're still in the -// process of implementing app layer crypto and this is temporary. Do not rely on the -// app layer crypto without changing this default. -const EnvImixEncryptKeyDefault = "I Don't care how small the room is I cast fireball" - var ( // EnvEnableTestData if set will populate the database with test data. // EnvEnableTestRunAndExit will start the application, but exit immediately after. @@ -206,13 +199,6 @@ func (cfg *Config) IsTestRunAndExitEnabled() bool { return EnvEnableTestRunAndExit.String() != "" } -func (cfg *Config) GetEncryptKey() []byte { - if EnvImixEncryptKey.String() == REDACTED { - return []byte(EnvImixEncryptKeyDefault) - } - return []byte(EnvImixEncryptKey.String()) -} - // ConfigureHTTPServer enables the configuration of the Tavern HTTP server. The endpoint field will be // overwritten with Tavern's HTTP handler when Tavern is run. func ConfigureHTTPServerFromEnv(options ...func(*http.Server)) func(*Config) { From 75285d3db3cc055958587ba37751d5a093cd050d Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 1 Jul 2024 00:56:11 +0000 Subject: [PATCH 102/141] Remove static key --- tavern/config.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/tavern/config.go b/tavern/config.go index c01ca4db2..83c4d45bf 100644 --- a/tavern/config.go +++ b/tavern/config.go @@ -73,9 +73,6 @@ var ( // EnvEnableMetrics enables the /metrics endpoint and HTTP server. It is unauthenticated and should be used carefully. EnvEnablePProf = EnvString{"ENABLE_PPROF", ""} EnvEnableMetrics = EnvString{"ENABLE_METRICS", ""} - - // EnvImixEncryptKey is the secret key used to encrypt app layer communication - EnvImixEncryptKey = EnvString{"IMIX_ENCRYPT_KEY", REDACTED} ) // Config holds information that controls the behaviour of Tavern From 8685ea75c64b47bb52a320d8c97bf2eef97758a7 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 1 Jul 2024 00:58:29 +0000 Subject: [PATCH 103/141] Remove static key bits. --- tavern/app.go | 1 - tavern/config.go | 2 -- terraform/main.tf | 16 ---------------- 3 files changed, 19 deletions(-) diff --git a/tavern/app.go b/tavern/app.go index 687f803cd..5d98f5f1d 100644 --- a/tavern/app.go +++ b/tavern/app.go @@ -329,7 +329,6 @@ func generate_key_pair() (*ecdh.PublicKey, *ecdh.PrivateKey) { func newGRPCHandler(client *ent.Client, grpcShellMux *stream.Mux) http.Handler { public_key, priv_key := generate_key_pair() log.Println("[INFO] Public key: ", base64.StdEncoding.EncodeToString(public_key.Bytes())) - log.Println("[INFO] Private key: ", base64.StdEncoding.EncodeToString(priv_key.Bytes())) c2srv := c2.New(client, grpcShellMux) xchacha := cryptocodec.StreamDecryptCodec{ Csvc: cryptocodec.NewCryptoSvc(priv_key), diff --git a/tavern/config.go b/tavern/config.go index 83c4d45bf..54531df05 100644 --- a/tavern/config.go +++ b/tavern/config.go @@ -20,8 +20,6 @@ import ( "realm.pub/tavern/tomes" ) -const REDACTED = "[REDACTED]" - var ( // EnvEnableTestData if set will populate the database with test data. // EnvEnableTestRunAndExit will start the application, but exit immediately after. diff --git a/terraform/main.tf b/terraform/main.tf index c740acfa1..0ee9cfa21 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -88,18 +88,6 @@ variable "enable_metrics" { description = "Enable prometheus sidecar and Tavern metrics collection" default = false } -// !!!! DANGER !!!!! -// This is the default static key set to ensure compatability between server and client -// in debug builds. This key must be changed in order to protect data. We're still in the -// process of implementing app layer crypto and this is temporary. Do not rely on the -// app layer crypto without changing this default. -variable "imix_encrypt_key" { - type = string - description = "The encryption key tavern and imix should use to talk to each other" - sensitive = true - default = "I Don't care how small the room is I cast fireball" -} - provider "google" { project = var.gcp_project @@ -211,10 +199,6 @@ resource "google_cloud_run_service" "tavern" { name = "ENABLE_METRICS" value = var.enable_metrics ? "1" : "" } - env { - name = "IMIX_ENCRYPT_KEY" - value = var.imix_encrypt_key - } } // Only create prometheus sidecar if metrics enabled From 6efef7b66faeb7bd0e509a60f842a615849e2f40 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 1 Jul 2024 01:06:14 +0000 Subject: [PATCH 104/141] Add launch.json --- .github/workflows/tests.yml | 1 + .vscode/launch.json | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 .vscode/launch.json diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1eb7d7208..3b65662bf 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -9,6 +9,7 @@ on: env: CARGO_TERM_COLOR: always + SERVER_PUBKEY: "pR56vDJZb9b3BL3ZvCXIvgK0r2vCk7FiZ1RjeEhJVyU=" jobs: tavern: diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..fc71cbbb4 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,10 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "env": { + "SERVER_PUBKEY": "pR56vDJZb9b3BL3ZvCXIvgK0r2vCk7FiZ1RjeEhJVyU=" + }, + } + ] +} From 40dd6182d734d44f4e608ce977586827884dc661 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 2 Jul 2024 01:52:39 +0000 Subject: [PATCH 105/141] Fix env! error --- .vscode/launch.json | 10 ---------- .vscode/settings.json | 3 +++ 2 files changed, 3 insertions(+), 10 deletions(-) delete mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index fc71cbbb4..000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "env": { - "SERVER_PUBKEY": "pR56vDJZb9b3BL3ZvCXIvgK0r2vCk7FiZ1RjeEhJVyU=" - }, - } - ] -} diff --git a/.vscode/settings.json b/.vscode/settings.json index 4fad2d189..f8e40f873 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,6 +3,9 @@ "--profile", "rust-analyzer" ], + "rust-analyzer.server.extraEnv": { + "SERVER_PUBKEY": "[OVERRIDE THIS VARIABLE]" + }, "rust-analyzer.check.command": "clippy", "rust-analyzer.showUnlinkedFileNotification": false, } From 58a6de5a6945078608ff53660f671aa0d5f8387b Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Thu, 4 Jul 2024 00:28:38 +0000 Subject: [PATCH 106/141] Stubbed out GCP KMS --- go.mod | 43 +++++++++--------- go.sum | 60 +++++++++++++++++++++++++ tavern/internal/secrets/gcp.go | 81 ++++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+), 20 deletions(-) create mode 100644 tavern/internal/secrets/gcp.go diff --git a/go.mod b/go.mod index fcd6f8c29..b3e8c2889 100644 --- a/go.mod +++ b/go.mod @@ -13,21 +13,24 @@ require ( github.com/hashicorp/go-multierror v1.1.1 github.com/mattn/go-sqlite3 v1.14.16 github.com/prometheus/client_golang v1.18.0 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 github.com/urfave/cli v1.22.5 github.com/vektah/gqlparser/v2 v2.5.10 - golang.org/x/crypto v0.21.0 - golang.org/x/net v0.22.0 - golang.org/x/oauth2 v0.18.0 - golang.org/x/sync v0.6.0 - google.golang.org/grpc v1.62.1 - google.golang.org/protobuf v1.33.0 + golang.org/x/crypto v0.24.0 + golang.org/x/net v0.26.0 + golang.org/x/oauth2 v0.21.0 + golang.org/x/sync v0.7.0 + google.golang.org/grpc v1.64.0 + google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v3 v3.0.1 ) require ( - cloud.google.com/go/iam v1.1.6 // indirect - cloud.google.com/go/pubsub v1.37.0 // indirect + cloud.google.com/go/auth v0.6.1 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect + cloud.google.com/go/iam v1.1.9 // indirect + cloud.google.com/go/pubsub v1.40.0 // indirect + cloud.google.com/go/secretmanager v1.13.3 // indirect dario.cat/mergo v1.0.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect @@ -44,7 +47,7 @@ require ( github.com/google/s2a-go v0.1.7 // indirect github.com/google/wire v0.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.2 // indirect + github.com/googleapis/gax-go/v2 v2.12.5 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect @@ -59,16 +62,16 @@ require ( go.opentelemetry.io/otel/trace v1.24.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect - google.golang.org/api v0.169.0 // indirect - google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240311173647-c811ad7063a7 // indirect + google.golang.org/api v0.187.0 // indirect + google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240624140628-dc46fd24d27d // indirect gopkg.in/warnings.v0 v0.1.2 // indirect ) require ( ariga.io/atlas v0.14.2 // indirect - cloud.google.com/go/compute v1.25.0 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/compute v1.27.1 // indirect + cloud.google.com/go/compute/metadata v0.3.0 // indirect github.com/agext/levenshtein v1.2.3 // indirect github.com/agnivade/levenshtein v1.1.1 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect @@ -97,10 +100,10 @@ require ( github.com/zclconf/go-cty v1.14.1 // indirect gocloud.dev v0.37.0 golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect - golang.org/x/mod v0.14.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/tools v0.17.0 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240311173647-c811ad7063a7 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d // indirect ) diff --git a/go.sum b/go.sum index 48f595113..b8c28db0f 100644 --- a/go.sum +++ b/go.sum @@ -2,14 +2,35 @@ ariga.io/atlas v0.14.2 h1:efxCuSGnDuhx7xm4JaqImR6xd+PqyizgGy5u/XUEI/g= ariga.io/atlas v0.14.2/go.mod h1:isZrlzJ5cpoCoKFoY9knZug7Lq4pP1cm8g3XciLZ0Pw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= +cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14= +cloud.google.com/go/auth v0.6.1 h1:T0Zw1XM5c1GlpN2HYr2s+m3vr1p2wy+8VN+Z1FKxW38= +cloud.google.com/go/auth v0.6.1/go.mod h1:eFHG7zDzbXHKmjJddFG/rBlcGp6t25SwRUiEQSlO4x4= +cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4= +cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= cloud.google.com/go/compute v1.25.0 h1:H1/4SqSUhjPFE7L5ddzHOfY2bCAvjwNRZPNl6Ni5oYU= cloud.google.com/go/compute v1.25.0/go.mod h1:GR7F0ZPZH8EhChlMo9FkLd7eUTwEymjqQagxzilIxIE= +cloud.google.com/go/compute v1.27.0 h1:EGawh2RUnfHT5g8f/FX3Ds6KZuIBC77hZoDrBvEZw94= +cloud.google.com/go/compute v1.27.0/go.mod h1:LG5HwRmWFKM2C5XxHRiNzkLLXW48WwvyVC0mfWsYPOM= +cloud.google.com/go/compute v1.27.1 h1:0WbBLIPNANheCRZ4h8QhgzjN53KMutbiVBOLtPiVzBU= +cloud.google.com/go/compute v1.27.1/go.mod h1:UVWm+bWKEKoM+PW2sZycP1Jgk3NhKwR2Iy2Cnp/G40I= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= +cloud.google.com/go/iam v1.1.8 h1:r7umDwhj+BQyz0ScZMp4QrGXjSTI3ZINnpgU2nlB/K0= +cloud.google.com/go/iam v1.1.8/go.mod h1:GvE6lyMmfxXauzNq8NbgJbeVQNspG+tcdL/W8QO1+zE= +cloud.google.com/go/iam v1.1.9 h1:oSkYLVtVme29uGYrOcKcvJRht7cHJpYD09GM9JaR0TE= +cloud.google.com/go/iam v1.1.9/go.mod h1:Nt1eDWNYH9nGQg3d/mY7U1hvfGmsaG9o/kLGoLoLXjQ= cloud.google.com/go/pubsub v1.37.0 h1:0uEEfaB1VIJzabPpwpZf44zWAKAme3zwKKxHk7vJQxQ= cloud.google.com/go/pubsub v1.37.0/go.mod h1:YQOQr1uiUM092EXwKs56OPT650nwnawc+8/IjoUeGzQ= +cloud.google.com/go/pubsub v1.39.0 h1:qt1+S6H+wwW8Q/YvDwM8lJnq+iIFgFEgaD/7h3lMsAI= +cloud.google.com/go/pubsub v1.39.0/go.mod h1:FrEnrSGU6L0Kh3iBaAbIUM8KMR7LqyEkMboVxGXCT+s= +cloud.google.com/go/pubsub v1.40.0 h1:0LdP+zj5XaPAGtWr2V6r88VXJlmtaB/+fde1q3TU8M0= +cloud.google.com/go/pubsub v1.40.0/go.mod h1:BVJI4sI2FyXp36KFKvFwcfDRDfR8MiLT8mMhmIhdAeA= +cloud.google.com/go/secretmanager v1.13.3 h1:VqUVYY3U6uFXOhPdZgAoZH9m8E6p7eK02TsDRj2SBf4= +cloud.google.com/go/secretmanager v1.13.3/go.mod h1:e45+CxK0w6GaL4hS+KabgQskl4RdSS30b+HRf0TH0kk= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= entgo.io/contrib v0.4.5 h1:BFaOHwFLE8WZjVJadP0XHCIaxgcC1BAtUvAyw7M/GHk= @@ -143,6 +164,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfF github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.12.2 h1:mhN09QQW1jEWeMF74zGR81R30z4VJzjZsfkUhuHF+DA= github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= +github.com/googleapis/gax-go/v2 v2.12.5 h1:8gw9KZK8TiVKB6q3zHY3SBzLnrGp6HQjyfYBYGmXdxA= +github.com/googleapis/gax-go/v2 v2.12.5/go.mod h1:BUDKcWo+RaKq5SC9vVYL0wLADa3VcfswbOMMRmB9H3E= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -205,6 +228,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -212,6 +236,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU= github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vektah/gqlparser/v2 v2.5.10 h1:6zSM4azXC9u4Nxy5YmdmGu4uKamfwsdKTwp5zsEealU= @@ -236,6 +262,7 @@ go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= +go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= gocloud.dev v0.37.0 h1:XF1rN6R0qZI/9DYjN16Uy0durAmSlf58DHOcb28GPro= @@ -250,6 +277,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= @@ -261,6 +290,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -279,9 +310,13 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -290,6 +325,8 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -311,6 +348,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -320,6 +359,7 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -332,6 +372,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -345,12 +387,16 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= google.golang.org/api v0.169.0 h1:QwWPy71FgMWqJN/l6jVlFHUa29a7dcUy02I8o799nPY= google.golang.org/api v0.169.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg= +google.golang.org/api v0.187.0 h1:Mxs7VATVC2v7CY+7Xwm4ndkX71hpElcvx0D1Ji/p1eo= +google.golang.org/api v0.187.0/go.mod h1:KIHlTc4x7N7gKKuVsdmfBXN13yEEWXWFURWY6SBp2gk= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= @@ -360,10 +406,20 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 h1:ImUcDPHjTrAqNhlOkSocDLfG9rrNHH7w7uoKWPaWZ8s= google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7/go.mod h1:/3XmxOjePkvmKrHuBy4zNFw7IzxJXtAgdpXi8Ll990U= +google.golang.org/genproto v0.0.0-20240624140628-dc46fd24d27d h1:PksQg4dV6Sem3/HkBX+Ltq8T0ke0PKIRBNBatoDTVls= +google.golang.org/genproto v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:s7iA721uChleev562UJO2OYB0PPT9CMFjV+Ce7VJH5M= +google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094 h1:6whtk83KtD3FkGrVb2hFXuQ+ZMbCNdakARIn/aHMmG8= +google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094/go.mod h1:Zs4wYw8z1zr6RNF4cwYb31mvN/EGaKAdQjNCF3DW6K4= google.golang.org/genproto/googleapis/api v0.0.0-20240311173647-c811ad7063a7 h1:oqta3O3AnlWbmIE3bFnWbu4bRxZjfbWCp0cKSuZh01E= google.golang.org/genproto/googleapis/api v0.0.0-20240311173647-c811ad7063a7/go.mod h1:VQW3tUculP/D4B+xVCo+VgSq8As6wA9ZjHl//pmk+6s= +google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4 h1:MuYw1wJzT+ZkybKfaOXKp5hJiZDn2iHaXRw0mRYdHSc= +google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4/go.mod h1:px9SlOOZBg1wM1zdnr8jEL4CNGUBZ+ZKYtNPApNQc4c= +google.golang.org/genproto/googleapis/api v0.0.0-20240624140628-dc46fd24d27d h1:Aqf0fiIdUQEj0Gn9mKFFXoQfTTEaNopWpfVyYADxiSg= +google.golang.org/genproto/googleapis/api v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:Od4k8V1LQSizPRUK4OzZ7TBE/20k+jPczUDAEyvn69Y= google.golang.org/genproto/googleapis/rpc v0.0.0-20240311173647-c811ad7063a7 h1:8EeVk1VKMD+GD/neyEHGmz7pFblqPjHoi+PGQIlLx2s= google.golang.org/genproto/googleapis/rpc v0.0.0-20240311173647-c811ad7063a7/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d h1:k3zyW3BYYR30e8v3x0bTDdE9vpYFjZHK+HcyqkrppWk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= @@ -371,6 +427,8 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= +google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -384,6 +442,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/tavern/internal/secrets/gcp.go b/tavern/internal/secrets/gcp.go new file mode 100644 index 000000000..7fcbba402 --- /dev/null +++ b/tavern/internal/secrets/gcp.go @@ -0,0 +1,81 @@ +package secrets + +import ( + "context" + "fmt" + "log" + + secretmanager "cloud.google.com/go/secretmanager/apiv1" + "cloud.google.com/go/secretmanager/apiv1/secretmanagerpb" +) + +type Gcp struct { + Name string + projectID string +} + +// GetName implements SecretsManager. +func (g Gcp) GetName() string { + return g.Name +} + +// GetValue implements SecretsManager. +func (g Gcp) GetValue(string) (string, error) { + panic("unimplemented") +} + +// SetValue implements SecretsManager. +func (g Gcp) SetValue(key string, value string) (string, error) { + // GCP project in which to store secrets in Secret Manager. + projectID := "your-project-id" + + // Create the client. + ctx := context.Background() + client, err := secretmanager.NewClient(ctx) + if err != nil { + log.Fatalf("failed to setup client: %v", err) + } + defer client.Close() + + // Create the request to create the secret. + createSecretReq := &secretmanagerpb.CreateSecretRequest{ + Parent: fmt.Sprintf("projects/%s", projectID), + SecretId: "my-secret", + Secret: &secretmanagerpb.Secret{ + Replication: &secretmanagerpb.Replication{ + Replication: &secretmanagerpb.Replication_Automatic_{ + Automatic: &secretmanagerpb.Replication_Automatic{}, + }, + }, + }, + } + + secret, err := client.CreateSecret(ctx, createSecretReq) + if err != nil { + log.Fatalf("failed to create secret: %v", err) + } + + // Declare the payload to store. + payload := []byte("my super secret data") + + // Build the request. + addSecretVersionReq := &secretmanagerpb.AddSecretVersionRequest{ + Parent: secret.Name, + Payload: &secretmanagerpb.SecretPayload{ + Data: payload, + }, + } + + // Call the API. + version, err := client.AddSecretVersion(ctx, addSecretVersionReq) + if err != nil { + log.Fatalf("failed to add secret version: %v", err) + } + +} + +func NewGcp() SecretsManager { + return Gcp{ + Name: "Gcp", + } +} From 0ebf641c39d19687bba20f87fd9537ae2836ff1a Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Sun, 7 Jul 2024 19:13:42 +0000 Subject: [PATCH 107/141] Implement gcp secret manager --- tavern/internal/secrets/debug_file_test.go | 7 +- tavern/internal/secrets/gcp.go | 127 +++++++++++++++++---- tavern/internal/secrets/gcp_test.go | 37 ++++++ 3 files changed, 145 insertions(+), 26 deletions(-) create mode 100644 tavern/internal/secrets/gcp_test.go diff --git a/tavern/internal/secrets/debug_file_test.go b/tavern/internal/secrets/debug_file_test.go index eb7d4d74d..d81fed992 100644 --- a/tavern/internal/secrets/debug_file_test.go +++ b/tavern/internal/secrets/debug_file_test.go @@ -29,7 +29,7 @@ secrets: return secretsPath } -func TestGetSecrets(t *testing.T) { +func TestGetSecretsFile(t *testing.T) { path := createTestSecrets(t) defer os.Remove(path) @@ -43,7 +43,7 @@ func TestGetSecrets(t *testing.T) { assert.Equal(t, "Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE=", res) } -func TestSetSecretsAdd(t *testing.T) { +func TestSetSecretsAddFile(t *testing.T) { path := createTestSecrets(t) defer os.Remove(path) @@ -73,7 +73,7 @@ func TestSetSecretsAdd(t *testing.T) { assert.Equal(t, "Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE=", res) } -func TestSetSecretsNew(t *testing.T) { +func TestSetSecretsNewFile(t *testing.T) { tmpDir := t.TempDir() path := path.Join(tmpDir, "secrets.yaml") defer os.Remove(path) @@ -82,6 +82,7 @@ func TestSetSecretsNew(t *testing.T) { res, err := secretsManager.GetValue("super_secret_test_data") // Make sure this fails assert.NotNil(t, err) + assert.Equal(t, "", res) res, err = secretsManager.SetValue("super_secret_test_data", "now this will work") assert.Nil(t, err) diff --git a/tavern/internal/secrets/gcp.go b/tavern/internal/secrets/gcp.go index 7fcbba402..66ab2e579 100644 --- a/tavern/internal/secrets/gcp.go +++ b/tavern/internal/secrets/gcp.go @@ -2,16 +2,23 @@ package secrets import ( "context" + "encoding/json" + "errors" "fmt" "log" + "strings" secretmanager "cloud.google.com/go/secretmanager/apiv1" "cloud.google.com/go/secretmanager/apiv1/secretmanagerpb" + "golang.org/x/oauth2/google" + "google.golang.org/api/compute/v1" ) type Gcp struct { Name string projectID string + client *secretmanager.Client + clientctx context.Context } // GetName implements SecretsManager. @@ -20,27 +27,56 @@ func (g Gcp) GetName() string { } // GetValue implements SecretsManager. -func (g Gcp) GetValue(string) (string, error) { - panic("unimplemented") +func (g Gcp) GetValue(key string) (string, error) { + // name := "projects/my-project/secrets/my-secret" + name := fmt.Sprintf("projects/%s/secrets/%s/versions/latest", g.projectID, key) + + // Build the request. + accessRequest := &secretmanagerpb.AccessSecretVersionRequest{ + Name: name, + } + + // Call the API. + result, err := g.client.AccessSecretVersion(g.clientctx, accessRequest) + if err != nil { + log.Printf("[ERROR] failed to access secret version: %v\n", err) + return "", err + } + + value := string(result.Payload.Data) + + return value, nil } -// SetValue implements SecretsManager. -func (g Gcp) SetValue(key string, value string) (string, error) { - // GCP project in which to store secrets in Secret Manager. - projectID := "your-project-id" +type credentialsJson struct { + ProjectID string `json:"quota_project_id"` +} - // Create the client. - ctx := context.Background() - client, err := secretmanager.NewClient(ctx) +func GetCurrentGcpProject(ctx context.Context) (string, error) { + respMesg, err := google.FindDefaultCredentials(ctx, compute.ComputeScope) if err != nil { - log.Fatalf("failed to setup client: %v", err) + return "", err } - defer client.Close() - // Create the request to create the secret. - createSecretReq := &secretmanagerpb.CreateSecretRequest{ - Parent: fmt.Sprintf("projects/%s", projectID), - SecretId: "my-secret", + // respMesg.ProjectID can be empty so instead we grab from the creds JSON file + credJSON := credentialsJson{} + err = json.Unmarshal(respMesg.JSON, &credJSON) + if err != nil { + return "", err + } + ProjectID := credJSON.ProjectID + + if ProjectID == "" { + return "", errors.New("project id is empty") + } + + return ProjectID, nil +} + +func (g Gcp) newCreateSecretReq(key string, parent string) secretmanagerpb.CreateSecretRequest { + return secretmanagerpb.CreateSecretRequest{ + Parent: parent, + SecretId: key, Secret: &secretmanagerpb.Secret{ Replication: &secretmanagerpb.Replication{ Replication: &secretmanagerpb.Replication_Automatic_{ @@ -49,33 +85,78 @@ func (g Gcp) SetValue(key string, value string) (string, error) { }, }, } +} - secret, err := client.CreateSecret(ctx, createSecretReq) +// SetValue implements SecretsManager. +func (g Gcp) SetValue(key string, value string) (string, error) { + // Create the request to create the secret. + parent := fmt.Sprintf("projects/%s", g.projectID) + createSecretReq := g.newCreateSecretReq(key, parent) + + old_value := "" + _, err := g.client.CreateSecret(g.clientctx, &createSecretReq) if err != nil { - log.Fatalf("failed to create secret: %v", err) + if !strings.Contains(err.Error(), "code = AlreadyExists") { + log.Printf("[ERROR] Failed to create secret: %v\n", err) + return "", err + } else { + tmp, err := g.GetValue(key) + if err != nil { + log.Printf("[ERROR] Failed to get old secret: %v\n", err) + return "", err + } + old_value = tmp + } } // Declare the payload to store. - payload := []byte("my super secret data") + path := fmt.Sprintf("%s/secrets/%s", parent, key) + payload := []byte(value) // Build the request. addSecretVersionReq := &secretmanagerpb.AddSecretVersionRequest{ - Parent: secret.Name, + Parent: path, Payload: &secretmanagerpb.SecretPayload{ Data: payload, }, } // Call the API. - version, err := client.AddSecretVersion(ctx, addSecretVersionReq) + version, err := g.client.AddSecretVersion(g.clientctx, addSecretVersionReq) if err != nil { log.Fatalf("failed to add secret version: %v", err) } + log.Printf("version: %v\n", version) + return old_value, nil } -func NewGcp() SecretsManager { - return Gcp{ - Name: "Gcp", +func NewGcp(projectID string) (SecretsManager, error) { + // GCP project in which to store secrets in Secret Manager. + ctx := context.Background() + + // If unset try to figure out the current GCP + if projectID == "" { + tmp, err := GetCurrentGcpProject(ctx) + projectID = tmp + if err != nil { + fmt.Printf("[ERROR] Failed to get current project ID: %v\n", err) + return nil, err + } + } + fmt.Printf("[DEBUG] Using projectID: %s\n", projectID) + + // Create the client. + client, err := secretmanager.NewClient(ctx) + if err != nil { + log.Printf("[ERROR] Failed to setup client: %v\n", err) + return nil, err } + + return Gcp{ + Name: "Gcp", + projectID: projectID, + client: client, + clientctx: ctx, + }, nil } diff --git a/tavern/internal/secrets/gcp_test.go b/tavern/internal/secrets/gcp_test.go new file mode 100644 index 000000000..616131e69 --- /dev/null +++ b/tavern/internal/secrets/gcp_test.go @@ -0,0 +1,37 @@ +package secrets_test + +// No way to test this in CI but worked in dev + +// import ( +// "testing" + +// "github.com/stretchr/testify/assert" +// "realm.pub/tavern/internal/secrets" +// ) + +// func TestSetSecretsGcp(t *testing.T) { +// test_key := "super_secret_test_data" +// // Create manager +// secretsManager, err := secrets.NewGcp("") +// assert.NotNil(t, secretsManager) +// assert.Nil(t, err) +// // Get a non existent value +// res, err := secretsManager.GetValue(test_key) +// assert.NotNil(t, err) +// assert.Equal(t, "", res) + +// // Create a value +// res, err = secretsManager.SetValue(test_key, "This should work") +// assert.Nil(t, err) +// assert.Equal(t, "", res) + +// // Update the value +// res, err = secretsManager.SetValue(test_key, "This should work too") +// assert.Nil(t, err) +// assert.Equal(t, "This should work", res) + +// // Get the value +// res, err = secretsManager.GetValue(test_key) +// assert.Nil(t, err) +// assert.Equal(t, "This should work too", res) +// } From d2f775963779b55007d86cf2a8242223758a7780 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Sun, 7 Jul 2024 21:33:01 +0000 Subject: [PATCH 108/141] switch to []byte --- .vscode/settings.json | 2 +- implants/lib/pb/src/xchacha.rs | 22 +++++----- tavern/app.go | 47 ++++++++++++++++++++-- tavern/internal/secrets/debug_file.go | 39 +++++++++--------- tavern/internal/secrets/debug_file_test.go | 40 +++++++++--------- tavern/internal/secrets/gcp.go | 35 +++++++--------- tavern/internal/secrets/gcp_test.go | 12 +++--- tavern/internal/secrets/secrets.go | 4 +- 8 files changed, 118 insertions(+), 83 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index f8e40f873..376f8d907 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,7 +4,7 @@ "rust-analyzer" ], "rust-analyzer.server.extraEnv": { - "SERVER_PUBKEY": "[OVERRIDE THIS VARIABLE]" + "IMIX_SERVER_PUBKEY": "[OVERRIDE THIS VARIABLE]" }, "rust-analyzer.check.command": "clippy", "rust-analyzer.showUnlinkedFileNotification": false, diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index d470fbebf..720d506d0 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -17,7 +17,7 @@ use tonic::{ }; use x25519_dalek::{EphemeralSecret, PublicKey}; -const SERVER_PUBKEY_STR: &str = env!("SERVER_PUBKEY"); +const SERVER_PUBKEY_STR: &str = env!("IMIX_SERVER_PUBKEY"); const SERVER_PUBKEY: [u8; 32] = const_decode::Base64.decode(SERVER_PUBKEY_STR.as_bytes()); // ------------ @@ -42,15 +42,9 @@ fn get_key(pub_key: [u8; 32]) -> Result<[u8; 32]> { // ------------ -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct ChaChaSvc {} -impl Default for ChaChaSvc { - fn default() -> Self { - Self {} - } -} - #[derive(Debug, Clone)] pub struct ChachaCodec(PhantomData<(T, U)>, ChaChaSvc); @@ -131,8 +125,8 @@ where }; // Write pubkey + nonce + cipher text - buf.writer().write_all(client_public.as_bytes()); - buf.writer().write_all(nonce.as_slice()); + buf.writer().write_all(client_public.as_bytes())?; + buf.writer().write_all(nonce.as_slice())?; buf.writer().write_all(ciphertext.as_slice())?; Ok(()) @@ -142,6 +136,8 @@ where // --- // const DEFAULT_CODEC_BUFFER_SIZE: usize = 8 * 1024; +const PUBKEY_LEN: usize = 32; +const NONCE_LEN: usize = 24; #[derive(Debug)] pub struct ChachaDecrypt(PhantomData<(T, U)>, ChaChaSvc); @@ -174,17 +170,17 @@ where .map_err(from_anyhow_error)?; let client_public = buf - .get(0..32) + .get(0..PUBKEY_LEN) .context("Input buffer doesn't have enough bytes for public key") .map_err(from_anyhow_error)?; let nonce = buf - .get(32..56) + .get(PUBKEY_LEN..PUBKEY_LEN + NONCE_LEN) .context("Input buffer doesn't have enough bytes for nonce") .map_err(from_anyhow_error)?; let ciphertext = buf - .get(56..) + .get(PUBKEY_LEN + NONCE_LEN..) .context("Input buffer doesn't have enough bytes for ciphertext") .map_err(from_anyhow_error)?; diff --git a/tavern/app.go b/tavern/app.go index 5d98f5f1d..76a2e8eaf 100644 --- a/tavern/app.go +++ b/tavern/app.go @@ -5,6 +5,7 @@ import ( "crypto/ecdh" "crypto/ed25519" "crypto/rand" + "crypto/x509" "encoding/base64" "encoding/json" "fmt" @@ -33,6 +34,7 @@ import ( "realm.pub/tavern/internal/graphql" tavernhttp "realm.pub/tavern/internal/http" "realm.pub/tavern/internal/http/stream" + "realm.pub/tavern/internal/secrets" "realm.pub/tavern/internal/www" "realm.pub/tavern/tomes" ) @@ -326,12 +328,51 @@ func generate_key_pair() (*ecdh.PublicKey, *ecdh.PrivateKey) { return public_key, priv_key } +func getKeyPair() (*ecdh.PublicKey, *ecdh.PrivateKey) { + x22519 := ecdh.X25519() + + // secretsManager, err := secrets.NewGcp("") + secretsManager, err := secrets.NewDebugFileSecrets("/etc/realm-secrets.txt") + if err != nil { + log.Printf("[ERROR] Unable to setup secrets manager\n") + } + + // Check if we already have a key + priv_key_string, err := secretsManager.GetValue("tavern_encryption_private_key") + if err != nil { + // Generate a new one if it doesn't exist + priv_key, pub_key := generate_key_pair() + _, err = secretsManager.SetValue("tavern_encryption_private_key", priv_key.Bytes()) + if err != nil { + log.Printf("[ERROR] Unable to set 'tavern_encryption_private_key' using secrets manager: %v", err) + return nil, nil + } + return priv_key, pub_key + } + + // Parse private key bytes + tmp, err := x509.ParsePKCS8PrivateKey(priv_key_string) + if err != nil { + log.Printf("[ERROR] Unable to parse private key %v\n", err) + } + priv_key := tmp.(*ecdh.PrivateKey) + + public_key, err := x22519.NewPublicKey(priv_key.PublicKey().Bytes()) + if err != nil { + log.Printf("[ERROR] Failed to generate public key: %v\n", err) + panic("[ERROR] Failed to generate public key") + } + + return public_key, priv_key +} + func newGRPCHandler(client *ent.Client, grpcShellMux *stream.Mux) http.Handler { - public_key, priv_key := generate_key_pair() - log.Println("[INFO] Public key: ", base64.StdEncoding.EncodeToString(public_key.Bytes())) + pub, priv := getKeyPair() + log.Println("[INFO] Public key: ", base64.StdEncoding.EncodeToString(pub.Bytes())) + c2srv := c2.New(client, grpcShellMux) xchacha := cryptocodec.StreamDecryptCodec{ - Csvc: cryptocodec.NewCryptoSvc(priv_key), + Csvc: cryptocodec.NewCryptoSvc(priv), } grpcSrv := grpc.NewServer( grpc.ForceServerCodec(xchacha), diff --git a/tavern/internal/secrets/debug_file.go b/tavern/internal/secrets/debug_file.go index 04aee10fd..68bc7da92 100644 --- a/tavern/internal/secrets/debug_file.go +++ b/tavern/internal/secrets/debug_file.go @@ -28,76 +28,79 @@ type DebugFileSecrets struct { Path string } -func NewDebugFileSecrets(path string) SecretsManager { +func NewDebugFileSecrets(path string) (SecretsManager, error) { return DebugFileSecrets{ Name: "DebugFileSecrets", Path: path, - } + }, nil } func (s DebugFileSecrets) GetName() string { return s.Name } -func (s DebugFileSecrets) SetValue(key string, value string) (string, error) { - path, err := s.createSecretsFile() +func (s DebugFileSecrets) SetValue(key string, value []byte) ([]byte, error) { + path, err := s.ensureSecretsFileExist() if err != nil { log.Printf("[ERROR] Failed to create secrets file %s: %v", path, err) - return "", err + return []byte{}, err } secrets, err := s.getYamlStruct(path) if err != nil { log.Printf("[ERROR] Failed to parse YAML file %s: %v", path, err) - return "", err + return []byte{}, err } - var old_value string = "" + var old_value []byte = []byte{} + log.Printf("[ERROR] Before: %v\n", secrets.Secrets) // If the value exists update it for idx, k := range secrets.Secrets { if k.Key == key { - secrets.Secrets[idx].Value = value - old_value = k.Value + secrets.Secrets[idx].Value = string(value) + old_value = []byte(k.Value) } } // If the value doesn't exist create it - if old_value == "" { + if len(old_value) == 0 { secrets.Secrets = append( secrets.Secrets, Secret{ Key: key, - Value: value, + Value: string(value), }, ) } + log.Printf("[ERROR] After: %v\n", secrets.Secrets) err = s.setYamlStruct(path, secrets) if err != nil { log.Printf("[ERROR] Failed to update YAML file %s: %v", path, err) - return "", err + return []byte{}, err } return old_value, nil } -func (s DebugFileSecrets) GetValue(key string) (string, error) { +func (s DebugFileSecrets) GetValue(key string) ([]byte, error) { path := s.Path secrets, err := s.getYamlStruct(path) if err != nil { log.Printf("[ERROR] Failed to parse YAML file %s: %v", path, err) - return "", err + return []byte{}, err } for _, k := range secrets.Secrets { + fmt.Printf("key: %s\n", k) if k.Key == key { - return k.Value, nil + return []byte(k.Value), nil } } - return "", nil + return []byte{}, nil } func (s DebugFileSecrets) setYamlStruct(path string, secrets Secrets) error { @@ -113,8 +116,6 @@ func (s DebugFileSecrets) setYamlStruct(path string, secrets Secrets) error { return err } - log.Printf("data: %s\n", data) - _, err = file.Write(data) if err != nil { log.Printf("[ERROR] Failed to read file %s: %v", path, err) @@ -150,7 +151,7 @@ func (s DebugFileSecrets) getYamlStruct(path string) (Secrets, error) { return secrets, nil } -func (s DebugFileSecrets) createSecretsFile() (string, error) { +func (s DebugFileSecrets) ensureSecretsFileExist() (string, error) { _, err := os.Stat(s.Path) if errors.Is(err, os.ErrNotExist) { // Create file diff --git a/tavern/internal/secrets/debug_file_test.go b/tavern/internal/secrets/debug_file_test.go index d81fed992..10b6a81b8 100644 --- a/tavern/internal/secrets/debug_file_test.go +++ b/tavern/internal/secrets/debug_file_test.go @@ -17,9 +17,9 @@ func createTestSecrets(t *testing.T) string { data := []byte(` secrets: - key: TAVERN_PRIVATE_KEY - value: Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE= + value: !!binary Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE= - key: super_secret_test_data - value: hello world! + value: !!binary NjggNjUgNmMgNmMgNmYgMjAgNzcgNmYgNzIgNmMgNjQgMjE= `) err := os.WriteFile(secretsPath, data, 0644) if err != nil { @@ -33,62 +33,66 @@ func TestGetSecretsFile(t *testing.T) { path := createTestSecrets(t) defer os.Remove(path) - secretsManager := secrets.NewDebugFileSecrets(path) + secretsManager, err := secrets.NewDebugFileSecrets(path) + assert.Nil(t, err) res, err := secretsManager.GetValue("super_secret_test_data") assert.Nil(t, err) - assert.Equal(t, "hello world!", res) + assert.Equal(t, []byte("hello world!"), res) res, err = secretsManager.GetValue("TAVERN_PRIVATE_KEY") assert.Nil(t, err) - assert.Equal(t, "Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE=", res) + assert.Equal(t, []byte("Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE="), res) } func TestSetSecretsAddFile(t *testing.T) { path := createTestSecrets(t) defer os.Remove(path) - secretsManager := secrets.NewDebugFileSecrets(path) - res, err := secretsManager.SetValue("WOAH!", "This works!") + secretsManager, err := secrets.NewDebugFileSecrets(path) + assert.Nil(t, err) + res, err := secretsManager.SetValue("WOAH!", []byte("This works!")) assert.Nil(t, err) - assert.Equal(t, "", res) + assert.Equal(t, []byte{}, res) res, err = secretsManager.GetValue("WOAH!") assert.Nil(t, err) - assert.Equal(t, "This works!", res) + assert.Equal(t, []byte("This works!"), res) // --- - res, err = secretsManager.SetValue("WOAH!", "This works too!") + res, err = secretsManager.SetValue("WOAH!", []byte("This works too!")) assert.Nil(t, err) - assert.Equal(t, "This works!", res) + assert.Equal(t, []byte("This works!"), res) res, err = secretsManager.GetValue("WOAH!") assert.Nil(t, err) - assert.Equal(t, "This works too!", res) + assert.Equal(t, []byte("This works too!"), res) // --- res, err = secretsManager.GetValue("TAVERN_PRIVATE_KEY") assert.Nil(t, err) - assert.Equal(t, "Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE=", res) + assert.Equal(t, []byte("Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE="), res) } func TestSetSecretsNewFile(t *testing.T) { tmpDir := t.TempDir() path := path.Join(tmpDir, "secrets.yaml") defer os.Remove(path) + // path = "/tmp/test-secrets.yaml" - secretsManager := secrets.NewDebugFileSecrets(path) + secretsManager, err := secrets.NewDebugFileSecrets(path) + assert.Nil(t, err) res, err := secretsManager.GetValue("super_secret_test_data") // Make sure this fails assert.NotNil(t, err) - assert.Equal(t, "", res) + assert.Equal(t, []byte{}, res) - res, err = secretsManager.SetValue("super_secret_test_data", "now this will work") + res, err = secretsManager.SetValue("super_secret_test_data", []byte{0x99, 0x99}) assert.Nil(t, err) - assert.Equal(t, "", res) + assert.Equal(t, []byte{}, res) res, err = secretsManager.GetValue("super_secret_test_data") assert.Nil(t, err) - assert.Equal(t, "now this will work", res) + assert.Equal(t, []byte{0x99, 0x99}, res) } diff --git a/tavern/internal/secrets/gcp.go b/tavern/internal/secrets/gcp.go index 66ab2e579..62bbf006c 100644 --- a/tavern/internal/secrets/gcp.go +++ b/tavern/internal/secrets/gcp.go @@ -27,7 +27,7 @@ func (g Gcp) GetName() string { } // GetValue implements SecretsManager. -func (g Gcp) GetValue(key string) (string, error) { +func (g Gcp) GetValue(key string) ([]byte, error) { // name := "projects/my-project/secrets/my-secret" name := fmt.Sprintf("projects/%s/secrets/%s/versions/latest", g.projectID, key) @@ -40,12 +40,10 @@ func (g Gcp) GetValue(key string) (string, error) { result, err := g.client.AccessSecretVersion(g.clientctx, accessRequest) if err != nil { log.Printf("[ERROR] failed to access secret version: %v\n", err) - return "", err + return []byte{}, err } - value := string(result.Payload.Data) - - return value, nil + return result.Payload.Data, nil } type credentialsJson struct { @@ -73,8 +71,11 @@ func GetCurrentGcpProject(ctx context.Context) (string, error) { return ProjectID, nil } -func (g Gcp) newCreateSecretReq(key string, parent string) secretmanagerpb.CreateSecretRequest { - return secretmanagerpb.CreateSecretRequest{ +// SetValue implements SecretsManager. +func (g Gcp) SetValue(key string, value []byte) ([]byte, error) { + // Create the request to create the secret. + parent := fmt.Sprintf("projects/%s", g.projectID) + createSecretReq := secretmanagerpb.CreateSecretRequest{ Parent: parent, SecretId: key, Secret: &secretmanagerpb.Secret{ @@ -85,25 +86,18 @@ func (g Gcp) newCreateSecretReq(key string, parent string) secretmanagerpb.Creat }, }, } -} - -// SetValue implements SecretsManager. -func (g Gcp) SetValue(key string, value string) (string, error) { - // Create the request to create the secret. - parent := fmt.Sprintf("projects/%s", g.projectID) - createSecretReq := g.newCreateSecretReq(key, parent) - old_value := "" + old_value := []byte{} _, err := g.client.CreateSecret(g.clientctx, &createSecretReq) if err != nil { if !strings.Contains(err.Error(), "code = AlreadyExists") { log.Printf("[ERROR] Failed to create secret: %v\n", err) - return "", err + return []byte{}, err } else { tmp, err := g.GetValue(key) if err != nil { log.Printf("[ERROR] Failed to get old secret: %v\n", err) - return "", err + return []byte{}, err } old_value = tmp } @@ -122,11 +116,10 @@ func (g Gcp) SetValue(key string, value string) (string, error) { } // Call the API. - version, err := g.client.AddSecretVersion(g.clientctx, addSecretVersionReq) + _, err = g.client.AddSecretVersion(g.clientctx, addSecretVersionReq) if err != nil { log.Fatalf("failed to add secret version: %v", err) } - log.Printf("version: %v\n", version) return old_value, nil } @@ -140,11 +133,11 @@ func NewGcp(projectID string) (SecretsManager, error) { tmp, err := GetCurrentGcpProject(ctx) projectID = tmp if err != nil { - fmt.Printf("[ERROR] Failed to get current project ID: %v\n", err) + log.Printf("[ERROR] Failed to get current project ID: %v\n", err) return nil, err } } - fmt.Printf("[DEBUG] Using projectID: %s\n", projectID) + log.Printf("[DEBUG] Using projectID: %s\n", projectID) // Create the client. client, err := secretmanager.NewClient(ctx) diff --git a/tavern/internal/secrets/gcp_test.go b/tavern/internal/secrets/gcp_test.go index 616131e69..a2f7080cd 100644 --- a/tavern/internal/secrets/gcp_test.go +++ b/tavern/internal/secrets/gcp_test.go @@ -18,20 +18,20 @@ package secrets_test // // Get a non existent value // res, err := secretsManager.GetValue(test_key) // assert.NotNil(t, err) -// assert.Equal(t, "", res) +// assert.Equal(t, []byte(""), res) // // Create a value -// res, err = secretsManager.SetValue(test_key, "This should work") +// res, err = secretsManager.SetValue(test_key, []byte("This should work")) // assert.Nil(t, err) -// assert.Equal(t, "", res) +// assert.Equal(t, []byte(""), res) // // Update the value -// res, err = secretsManager.SetValue(test_key, "This should work too") +// res, err = secretsManager.SetValue(test_key, []byte{0x99, 0x99}) // assert.Nil(t, err) -// assert.Equal(t, "This should work", res) +// assert.Equal(t, []byte("This should work"), res) // // Get the value // res, err = secretsManager.GetValue(test_key) // assert.Nil(t, err) -// assert.Equal(t, "This should work too", res) +// assert.Equal(t, []byte{0x99, 0x99}, res) // } diff --git a/tavern/internal/secrets/secrets.go b/tavern/internal/secrets/secrets.go index 99c765aed..0cfb8c22d 100644 --- a/tavern/internal/secrets/secrets.go +++ b/tavern/internal/secrets/secrets.go @@ -2,6 +2,6 @@ package secrets type SecretsManager interface { GetName() string - SetValue(string, string) (string, error) - GetValue(string) (string, error) + SetValue(string, []byte) ([]byte, error) + GetValue(string) ([]byte, error) } From 60d40e4bee0900183010245a690f803778c6d7db Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Sun, 7 Jul 2024 21:48:04 +0000 Subject: [PATCH 109/141] key stays the same between reboots. --- tavern/app.go | 15 ++++++++++----- tavern/internal/secrets/debug_file.go | 3 --- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/tavern/app.go b/tavern/app.go index 76a2e8eaf..2a472219e 100644 --- a/tavern/app.go +++ b/tavern/app.go @@ -331,8 +331,8 @@ func generate_key_pair() (*ecdh.PublicKey, *ecdh.PrivateKey) { func getKeyPair() (*ecdh.PublicKey, *ecdh.PrivateKey) { x22519 := ecdh.X25519() - // secretsManager, err := secrets.NewGcp("") - secretsManager, err := secrets.NewDebugFileSecrets("/etc/realm-secrets.txt") + secretsManager, err := secrets.NewGcp("") + // secretsManager, err := secrets.NewDebugFileSecrets("/etc/realm-secrets.txt") if err != nil { log.Printf("[ERROR] Unable to setup secrets manager\n") } @@ -341,13 +341,18 @@ func getKeyPair() (*ecdh.PublicKey, *ecdh.PrivateKey) { priv_key_string, err := secretsManager.GetValue("tavern_encryption_private_key") if err != nil { // Generate a new one if it doesn't exist - priv_key, pub_key := generate_key_pair() - _, err = secretsManager.SetValue("tavern_encryption_private_key", priv_key.Bytes()) + pub_key, priv_key := generate_key_pair() + priv_key_bytes, err := x509.MarshalPKCS8PrivateKey(priv_key) + if err != nil { + log.Printf("[ERROR] Unable to set marshal priv key: %v", err) + return nil, nil + } + _, err = secretsManager.SetValue("tavern_encryption_private_key", priv_key_bytes) if err != nil { log.Printf("[ERROR] Unable to set 'tavern_encryption_private_key' using secrets manager: %v", err) return nil, nil } - return priv_key, pub_key + return pub_key, priv_key } // Parse private key bytes diff --git a/tavern/internal/secrets/debug_file.go b/tavern/internal/secrets/debug_file.go index 68bc7da92..a988eee3d 100644 --- a/tavern/internal/secrets/debug_file.go +++ b/tavern/internal/secrets/debug_file.go @@ -54,7 +54,6 @@ func (s DebugFileSecrets) SetValue(key string, value []byte) ([]byte, error) { var old_value []byte = []byte{} - log.Printf("[ERROR] Before: %v\n", secrets.Secrets) // If the value exists update it for idx, k := range secrets.Secrets { if k.Key == key { @@ -73,7 +72,6 @@ func (s DebugFileSecrets) SetValue(key string, value []byte) ([]byte, error) { }, ) } - log.Printf("[ERROR] After: %v\n", secrets.Secrets) err = s.setYamlStruct(path, secrets) if err != nil { @@ -94,7 +92,6 @@ func (s DebugFileSecrets) GetValue(key string) ([]byte, error) { } for _, k := range secrets.Secrets { - fmt.Printf("key: %s\n", k) if k.Key == key { return []byte(k.Value), nil } From c9c7103f8df5536e901e37d88e08a4d57b50ed64 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Sun, 7 Jul 2024 23:41:35 +0000 Subject: [PATCH 110/141] Add prefix --- tavern/internal/secrets/gcp.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tavern/internal/secrets/gcp.go b/tavern/internal/secrets/gcp.go index 62bbf006c..c79c27b6a 100644 --- a/tavern/internal/secrets/gcp.go +++ b/tavern/internal/secrets/gcp.go @@ -17,6 +17,7 @@ import ( type Gcp struct { Name string projectID string + prefix string client *secretmanager.Client clientctx context.Context } @@ -29,7 +30,7 @@ func (g Gcp) GetName() string { // GetValue implements SecretsManager. func (g Gcp) GetValue(key string) ([]byte, error) { // name := "projects/my-project/secrets/my-secret" - name := fmt.Sprintf("projects/%s/secrets/%s/versions/latest", g.projectID, key) + name := fmt.Sprintf("projects/%s/secrets/%s_%s/versions/latest", g.projectID, g.prefix, key) // Build the request. accessRequest := &secretmanagerpb.AccessSecretVersionRequest{ @@ -77,7 +78,7 @@ func (g Gcp) SetValue(key string, value []byte) ([]byte, error) { parent := fmt.Sprintf("projects/%s", g.projectID) createSecretReq := secretmanagerpb.CreateSecretRequest{ Parent: parent, - SecretId: key, + SecretId: fmt.Sprintf("%s_%s", g.prefix, key), Secret: &secretmanagerpb.Secret{ Replication: &secretmanagerpb.Replication{ Replication: &secretmanagerpb.Replication_Automatic_{ @@ -104,7 +105,7 @@ func (g Gcp) SetValue(key string, value []byte) ([]byte, error) { } // Declare the payload to store. - path := fmt.Sprintf("%s/secrets/%s", parent, key) + path := fmt.Sprintf("%s/secrets/%s_%s", parent, g.prefix, key) payload := []byte(value) // Build the request. @@ -149,6 +150,7 @@ func NewGcp(projectID string) (SecretsManager, error) { return Gcp{ Name: "Gcp", projectID: projectID, + prefix: "REALM", client: client, clientctx: ctx, }, nil From e4cda417e68b3204d0c7717a155933f27e4837be Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 8 Jul 2024 23:20:13 -0400 Subject: [PATCH 111/141] Debugging --- tavern/internal/secrets/gcp.go | 1 + terraform/main.tf | 44 ++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/tavern/internal/secrets/gcp.go b/tavern/internal/secrets/gcp.go index c79c27b6a..474f8fe6a 100644 --- a/tavern/internal/secrets/gcp.go +++ b/tavern/internal/secrets/gcp.go @@ -53,6 +53,7 @@ type credentialsJson struct { func GetCurrentGcpProject(ctx context.Context) (string, error) { respMesg, err := google.FindDefaultCredentials(ctx, compute.ComputeScope) + log.Printf("[DEBUG] Default creds: %v\n", respMesg) if err != nil { return "", err } diff --git a/terraform/main.tf b/terraform/main.tf index 0ee9cfa21..f5155c114 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -31,6 +31,11 @@ variable "gcp_project" { error_message = "Must provide a valid gcp_project" } } + +data "google_project" "project" { + project_id = var.gcp_project +} + variable "gcp_region" { type = string description = "GCP Region for deployment" @@ -104,6 +109,11 @@ resource "google_project_service" "cloud_run_api" { disable_on_destroy = false } +resource "google_project_service" "secret_manager" { + service = "secretmanager.googleapis.com" + disable_on_destroy = false +} + resource "google_project_service" "cloud_sqladmin_api" { service = "sqladmin.googleapis.com" disable_on_destroy = false @@ -146,6 +156,36 @@ locals { prometheus_container_name = "prometheus-sidecar" } +resource "google_service_account" "svctavern" { + account_id = "svctavern" + description = "The service account Realm's Tavern uses to connect to GCP based services. Managed by Terraform." +} + +resource "google_secret_manager_secret" "tavern-grpc-priv-key" { + secret_id = "tavern_encryption_private_key" + + replication { + auto { + } + } +} + +resource "google_secret_manager_secret_iam_binding" "tavern-secrets-binding" { + project = var.gcp_project + secret_id = google_secret_manager_secret.tavern-grpc-priv-key.secret_id + role = "roles/secretmanager.secretAccessor" + members = [ + "serviceAccount:${google_service_account.svctavern.email}", + ] +} + +resource "google_project_iam_member" "tavern-sqlclient-binding" { + project = var.gcp_project + role = "roles/cloudsql.client" + member = "serviceAccount:${google_service_account.svctavern.email}" +} + + resource "google_cloud_run_service" "tavern" { name = "tavern" location = var.gcp_region @@ -157,6 +197,8 @@ resource "google_cloud_run_service" "tavern" { template { spec { + service_account_name = google_service_account.svctavern.email + containers { name = local.tavern_container_name image = var.tavern_container_image @@ -230,6 +272,8 @@ resource "google_cloud_run_service" "tavern" { autogenerate_revision_name = true depends_on = [ + google_project_iam_member.tavern-sqlclient-binding, + google_secret_manager_secret_iam_binding.tavern-secrets-binding, google_project_service.cloud_run_api, google_project_service.cloud_sqladmin_api, google_sql_user.tavern-user, From ba3dd191cead6fe0128f4a3084b125539de72681 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 8 Jul 2024 23:25:34 -0400 Subject: [PATCH 112/141] Check another way --- tavern/internal/secrets/gcp.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tavern/internal/secrets/gcp.go b/tavern/internal/secrets/gcp.go index 474f8fe6a..a0ef86907 100644 --- a/tavern/internal/secrets/gcp.go +++ b/tavern/internal/secrets/gcp.go @@ -53,11 +53,14 @@ type credentialsJson struct { func GetCurrentGcpProject(ctx context.Context) (string, error) { respMesg, err := google.FindDefaultCredentials(ctx, compute.ComputeScope) - log.Printf("[DEBUG] Default creds: %v\n", respMesg) if err != nil { return "", err } + if respMesg.ProjectID != "" { + return respMesg.ProjectID, nil + } + // respMesg.ProjectID can be empty so instead we grab from the creds JSON file credJSON := credentialsJson{} err = json.Unmarshal(respMesg.JSON, &credJSON) From ecda3b06398af904297b3a98b32da0092eb46272 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 8 Jul 2024 23:28:38 -0400 Subject: [PATCH 113/141] Fix secret name --- terraform/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terraform/main.tf b/terraform/main.tf index f5155c114..80ff67c54 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -162,7 +162,7 @@ resource "google_service_account" "svctavern" { } resource "google_secret_manager_secret" "tavern-grpc-priv-key" { - secret_id = "tavern_encryption_private_key" + secret_id = "REALM_tavern_encryption_private_key" replication { auto { From 438f7ab782e1594f2d3b80dc46ad1ebaeef2ebef Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 9 Jul 2024 21:04:47 +0000 Subject: [PATCH 114/141] Don't try to create secrets --- tavern/internal/secrets/gcp.go | 50 ++++++++++++++++------------------ 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/tavern/internal/secrets/gcp.go b/tavern/internal/secrets/gcp.go index a0ef86907..9f2934e7d 100644 --- a/tavern/internal/secrets/gcp.go +++ b/tavern/internal/secrets/gcp.go @@ -80,32 +80,30 @@ func GetCurrentGcpProject(ctx context.Context) (string, error) { func (g Gcp) SetValue(key string, value []byte) ([]byte, error) { // Create the request to create the secret. parent := fmt.Sprintf("projects/%s", g.projectID) - createSecretReq := secretmanagerpb.CreateSecretRequest{ - Parent: parent, - SecretId: fmt.Sprintf("%s_%s", g.prefix, key), - Secret: &secretmanagerpb.Secret{ - Replication: &secretmanagerpb.Replication{ - Replication: &secretmanagerpb.Replication_Automatic_{ - Automatic: &secretmanagerpb.Replication_Automatic{}, - }, - }, - }, - } - - old_value := []byte{} - _, err := g.client.CreateSecret(g.clientctx, &createSecretReq) - if err != nil { - if !strings.Contains(err.Error(), "code = AlreadyExists") { - log.Printf("[ERROR] Failed to create secret: %v\n", err) - return []byte{}, err - } else { - tmp, err := g.GetValue(key) - if err != nil { - log.Printf("[ERROR] Failed to get old secret: %v\n", err) - return []byte{}, err - } - old_value = tmp - } + // createSecretReq := secretmanagerpb.CreateSecretRequest{ + // Parent: parent, + // SecretId: fmt.Sprintf("%s_%s", g.prefix, key), + // Secret: &secretmanagerpb.Secret{ + // Replication: &secretmanagerpb.Replication{ + // Replication: &secretmanagerpb.Replication_Automatic_{ + // Automatic: &secretmanagerpb.Replication_Automatic{}, + // }, + // }, + // }, + // } + + // _, err := g.client.CreateSecret(g.clientctx, &createSecretReq) + // if err != nil { + // if !strings.Contains(err.Error(), "code = AlreadyExists") { + // log.Printf("[ERROR] Failed to create secret: %v\n", err) + // return []byte{}, err + // } else { + // } + + old_value, err := g.GetValue(key) + if err != nil && !strings.Contains(err.Error(), "code = NotFound") { + log.Printf("[ERROR] Failed to get old secret: %v\n", err) + return []byte{}, err } // Declare the payload to store. From 439cb3e1fbe9df73a0ac80a068d191034b3c230e Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 9 Jul 2024 17:39:35 -0400 Subject: [PATCH 115/141] And the peasants rejoice --- tavern/internal/secrets/gcp.go | 2 +- terraform/main.tf | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/tavern/internal/secrets/gcp.go b/tavern/internal/secrets/gcp.go index 9f2934e7d..a9237210d 100644 --- a/tavern/internal/secrets/gcp.go +++ b/tavern/internal/secrets/gcp.go @@ -98,7 +98,7 @@ func (g Gcp) SetValue(key string, value []byte) ([]byte, error) { // log.Printf("[ERROR] Failed to create secret: %v\n", err) // return []byte{}, err // } else { - // } + // }h old_value, err := g.GetValue(key) if err != nil && !strings.Contains(err.Error(), "code = NotFound") { diff --git a/terraform/main.tf b/terraform/main.tf index 80ff67c54..e672a432f 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -185,6 +185,18 @@ resource "google_project_iam_member" "tavern-sqlclient-binding" { member = "serviceAccount:${google_service_account.svctavern.email}" } +resource "google_project_iam_member" "tavern-metricwriter-binding" { + project = var.gcp_project + role = "roles/monitoring.metricWriter" + member = "serviceAccount:${google_service_account.svctavern.email}" +} + +resource "google_project_iam_member" "tavern-logwriter-binding" { + project = var.gcp_project + role = "roles/logging.logWriter" + member = "serviceAccount:${google_service_account.svctavern.email}" +} + resource "google_cloud_run_service" "tavern" { name = "tavern" @@ -274,6 +286,8 @@ resource "google_cloud_run_service" "tavern" { depends_on = [ google_project_iam_member.tavern-sqlclient-binding, google_secret_manager_secret_iam_binding.tavern-secrets-binding, + google_project_iam_member.tavern-metricwriter-binding, + google_project_iam_member.tavern-logwriter-binding, google_project_service.cloud_run_api, google_project_service.cloud_sqladmin_api, google_sql_user.tavern-user, From 6ab79d1dd2884b783ee96149233143762392c412 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 9 Jul 2024 21:48:05 +0000 Subject: [PATCH 116/141] Remove create secret code --- tavern/internal/secrets/gcp.go | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/tavern/internal/secrets/gcp.go b/tavern/internal/secrets/gcp.go index a9237210d..f9b894cb2 100644 --- a/tavern/internal/secrets/gcp.go +++ b/tavern/internal/secrets/gcp.go @@ -80,25 +80,6 @@ func GetCurrentGcpProject(ctx context.Context) (string, error) { func (g Gcp) SetValue(key string, value []byte) ([]byte, error) { // Create the request to create the secret. parent := fmt.Sprintf("projects/%s", g.projectID) - // createSecretReq := secretmanagerpb.CreateSecretRequest{ - // Parent: parent, - // SecretId: fmt.Sprintf("%s_%s", g.prefix, key), - // Secret: &secretmanagerpb.Secret{ - // Replication: &secretmanagerpb.Replication{ - // Replication: &secretmanagerpb.Replication_Automatic_{ - // Automatic: &secretmanagerpb.Replication_Automatic{}, - // }, - // }, - // }, - // } - - // _, err := g.client.CreateSecret(g.clientctx, &createSecretReq) - // if err != nil { - // if !strings.Contains(err.Error(), "code = AlreadyExists") { - // log.Printf("[ERROR] Failed to create secret: %v\n", err) - // return []byte{}, err - // } else { - // }h old_value, err := g.GetValue(key) if err != nil && !strings.Contains(err.Error(), "code = NotFound") { From 6c6635121b91a32c7ca99ac3bc815e99ca7bf68d Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 9 Jul 2024 21:56:58 +0000 Subject: [PATCH 117/141] Remove debug print --- tavern/internal/cryptocodec/cryptocodec.go | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/tavern/internal/cryptocodec/cryptocodec.go b/tavern/internal/cryptocodec/cryptocodec.go index d09fb21db..ae97f4197 100644 --- a/tavern/internal/cryptocodec/cryptocodec.go +++ b/tavern/internal/cryptocodec/cryptocodec.go @@ -5,7 +5,6 @@ import ( "crypto/ecdh" "crypto/rand" "errors" - "fmt" "log" "runtime" "strconv" @@ -96,17 +95,16 @@ func (csvc *CryptoSvc) SetAgentPubkey(client_pub_key []byte) { } func (csvc *CryptoSvc) generate_shared_key(client_pub_key_bytes []byte) []byte { - fmt.Println("[DEBUG] client_pub_key_bytes: ", client_pub_key_bytes) x22519_curve := ecdh.X25519() client_pub_key, err := x22519_curve.NewPublicKey(client_pub_key_bytes) if err != nil { - log.Printf("[ERROR] Failed to create public key %v", err) + log.Printf("[ERROR] Failed to create public key %v\n", err) return FAILURE_BYTES } shared_key, err := csvc.priv_key.ECDH(client_pub_key) if err != nil { - log.Printf("[ERROR] Failed to get shared secret %v", err) + log.Printf("[ERROR] Failed to get shared secret %v\n", err) return FAILURE_BYTES } @@ -116,7 +114,7 @@ func (csvc *CryptoSvc) generate_shared_key(client_pub_key_bytes []byte) []byte { func (csvc *CryptoSvc) Decrypt(in_arr []byte) ([]byte, []byte) { // Read in pub key if len(in_arr) < x25519.Size { - fmt.Printf("Input bytes to short %d expected at least %d\n", len(in_arr), x25519.Size) + log.Printf("[ERROR] Input bytes to short %d expected at least %d\n", len(in_arr), x25519.Size) return FAILURE_BYTES, FAILURE_BYTES } @@ -126,10 +124,9 @@ func (csvc *CryptoSvc) Decrypt(in_arr []byte) ([]byte, []byte) { // Generate shared secret derived_key := csvc.generate_shared_key(client_pub_key_bytes) - log.Println("[DEBUG] derived_key: ", derived_key) aead, err := chacha20poly1305.NewX(derived_key) if err != nil { - log.Printf("[ERROR] Failed to create xchacha key %v", err) + log.Printf("[ERROR] Failed to create xchacha key %v\n", err) return FAILURE_BYTES, FAILURE_BYTES } @@ -138,7 +135,7 @@ func (csvc *CryptoSvc) Decrypt(in_arr []byte) ([]byte, []byte) { // Read nonce if len(in_arr) < aead.NonceSize() { - fmt.Printf("Input bytes to short %d expected at least %d\n", len(in_arr), aead.NonceSize()) + log.Printf("[ERROR] Input bytes to short %d expected at least %d\n", len(in_arr), aead.NonceSize()) return FAILURE_BYTES, FAILURE_BYTES } nonce, ciphertext := in_arr[:aead.NonceSize()], in_arr[aead.NonceSize():] @@ -146,7 +143,7 @@ func (csvc *CryptoSvc) Decrypt(in_arr []byte) ([]byte, []byte) { // Decrypt plaintext, err := aead.Open(nil, nonce, ciphertext, nil) if err != nil { - fmt.Printf("Failed to decrypt %v\n", err) + log.Printf("[ERROR] Failed to decrypt %v\n", err) return FAILURE_BYTES, FAILURE_BYTES } @@ -157,19 +154,18 @@ func (csvc *CryptoSvc) Decrypt(in_arr []byte) ([]byte, []byte) { func (csvc *CryptoSvc) Encrypt(in_arr []byte) []byte { // Get the client pub key? client_pub_key_bytes := csvc.GetAgentPubkey() - fmt.Println("[DEBUG] Got pub key: ", client_pub_key_bytes) // Generate shared secret shared_key := csvc.generate_shared_key(client_pub_key_bytes) aead, err := chacha20poly1305.NewX(shared_key) if err != nil { - log.Printf("[ERROR] Failed to create xchacha key %v", err) + log.Printf("[ERROR] Failed to create xchacha key %v\n", err) return FAILURE_BYTES } nonce := make([]byte, aead.NonceSize(), aead.NonceSize()+len(in_arr)+aead.Overhead()) if _, err := rand.Read(nonce); err != nil { - fmt.Printf("Failed to encrypt %v\n", err) + log.Printf("[ERROR] Failed to encrypt %v\n", err) return FAILURE_BYTES } encryptedMsg := aead.Seal(nonce, nonce, in_arr, nil) From e7965cc47a35b76298e06542649e3b3ca572bde9 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 9 Jul 2024 22:09:20 +0000 Subject: [PATCH 118/141] Fix tests --- tavern/internal/secrets/debug_file_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tavern/internal/secrets/debug_file_test.go b/tavern/internal/secrets/debug_file_test.go index 10b6a81b8..167f12eb9 100644 --- a/tavern/internal/secrets/debug_file_test.go +++ b/tavern/internal/secrets/debug_file_test.go @@ -19,7 +19,7 @@ secrets: - key: TAVERN_PRIVATE_KEY value: !!binary Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE= - key: super_secret_test_data - value: !!binary NjggNjUgNmMgNmMgNmYgMjAgNzcgNmYgNzIgNmMgNjQgMjE= + value: hello world! `) err := os.WriteFile(secretsPath, data, 0644) if err != nil { @@ -41,7 +41,7 @@ func TestGetSecretsFile(t *testing.T) { res, err = secretsManager.GetValue("TAVERN_PRIVATE_KEY") assert.Nil(t, err) - assert.Equal(t, []byte("Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE="), res) + assert.Equal(t, []byte{0x15, 0xef, 0x04, 0xfd, 0x25, 0x5f, 0xec, 0xc2, 0xe0, 0x08, 0x7c, 0xc1, 0x5a, 0xf8, 0xdd, 0x9d, 0xab, 0xde, 0x8e, 0xc2, 0x62, 0x8c, 0x96, 0x43, 0xf6, 0x63, 0xef, 0x2d, 0x06, 0xe0, 0xc9, 0xb1}, res) } func TestSetSecretsAddFile(t *testing.T) { @@ -72,7 +72,7 @@ func TestSetSecretsAddFile(t *testing.T) { res, err = secretsManager.GetValue("TAVERN_PRIVATE_KEY") assert.Nil(t, err) - assert.Equal(t, []byte("Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE="), res) + assert.Equal(t, []byte{0x15, 0xef, 0x04, 0xfd, 0x25, 0x5f, 0xec, 0xc2, 0xe0, 0x08, 0x7c, 0xc1, 0x5a, 0xf8, 0xdd, 0x9d, 0xab, 0xde, 0x8e, 0xc2, 0x62, 0x8c, 0x96, 0x43, 0xf6, 0x63, 0xef, 0x2d, 0x06, 0xe0, 0xc9, 0xb1}, res) } func TestSetSecretsNewFile(t *testing.T) { From dd7914dd1de482184822f694854b80ad86710d61 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 9 Jul 2024 22:22:50 +0000 Subject: [PATCH 119/141] Secrets manager defaults --- tavern/app.go | 25 ++++++++++++++++++------- tavern/config.go | 3 +++ tavern/main_test.go | 1 + 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/tavern/app.go b/tavern/app.go index 2a472219e..9efa86933 100644 --- a/tavern/app.go +++ b/tavern/app.go @@ -312,27 +312,33 @@ func newGraphQLHandler(client *ent.Client, repoImporter graphql.RepoImporter) ht }) } -func generate_key_pair() (*ecdh.PublicKey, *ecdh.PrivateKey) { +func generate_key_pair() (*ecdh.PublicKey, *ecdh.PrivateKey, error) { x22519 := ecdh.X25519() priv_key, err := x22519.GenerateKey(rand.Reader) if err != nil { log.Printf("[ERROR] Failed to generate private key: %v\n", err) - panic("[ERROR] Failed to generate private key") + return nil, nil, err } public_key, err := x22519.NewPublicKey(priv_key.PublicKey().Bytes()) if err != nil { log.Printf("[ERROR] Failed to generate public key: %v\n", err) - panic("[ERROR] Failed to generate public key") + return nil, nil, err } - return public_key, priv_key + return public_key, priv_key, nil } func getKeyPair() (*ecdh.PublicKey, *ecdh.PrivateKey) { x22519 := ecdh.X25519() - secretsManager, err := secrets.NewGcp("") - // secretsManager, err := secrets.NewDebugFileSecrets("/etc/realm-secrets.txt") + var secretsManager secrets.SecretsManager + var err error + + if EnvSecretsManagerPath.String() == "" { + secretsManager, err = secrets.NewGcp("") + } else { + secretsManager, err = secrets.NewDebugFileSecrets(EnvSecretsManagerPath.String()) + } if err != nil { log.Printf("[ERROR] Unable to setup secrets manager\n") } @@ -341,7 +347,12 @@ func getKeyPair() (*ecdh.PublicKey, *ecdh.PrivateKey) { priv_key_string, err := secretsManager.GetValue("tavern_encryption_private_key") if err != nil { // Generate a new one if it doesn't exist - pub_key, priv_key := generate_key_pair() + pub_key, priv_key, err := generate_key_pair() + if err != nil { + log.Printf("[ERROR] Key generation failed: %v", err) + return nil, nil + } + priv_key_bytes, err := x509.MarshalPKCS8PrivateKey(priv_key) if err != nil { log.Printf("[ERROR] Unable to set marshal priv key: %v", err) diff --git a/tavern/config.go b/tavern/config.go index 54531df05..890012286 100644 --- a/tavern/config.go +++ b/tavern/config.go @@ -71,6 +71,9 @@ var ( // EnvEnableMetrics enables the /metrics endpoint and HTTP server. It is unauthenticated and should be used carefully. EnvEnablePProf = EnvString{"ENABLE_PPROF", ""} EnvEnableMetrics = EnvString{"ENABLE_METRICS", ""} + + // EnvSecretsManagerPath defines the local path on disk where secrets should be stored by the DebugFile secrets manager. If left empty uses GCP + EnvSecretsManagerPath = EnvString{"SECRETS_FILE_PATH", ""} ) // Config holds information that controls the behaviour of Tavern diff --git a/tavern/main_test.go b/tavern/main_test.go index c72d524f8..48517e870 100644 --- a/tavern/main_test.go +++ b/tavern/main_test.go @@ -13,6 +13,7 @@ func TestMainFunc(t *testing.T) { os.Setenv(EnvHTTPMetricsListenAddr.Key, "127.0.0.1:8081") os.Setenv(EnvEnablePProf.Key, "1") os.Setenv(EnvEnableMetrics.Key, "1") + os.Setenv(EnvSecretsManagerPath.Key, "/tmp/test-secret.yml") defer func() { unsetList := []string{ EnvEnableTestRunAndExit.Key, From 631acaab5db7bac0e089f204424038da317af90e Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 9 Jul 2024 23:01:54 +0000 Subject: [PATCH 120/141] Add env var to tests --- .github/workflows/tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3b65662bf..41535c725 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -9,7 +9,6 @@ on: env: CARGO_TERM_COLOR: always - SERVER_PUBKEY: "pR56vDJZb9b3BL3ZvCXIvgK0r2vCk7FiZ1RjeEhJVyU=" jobs: tavern: @@ -36,6 +35,8 @@ jobs: implants: runs-on: ${{ matrix.os }} timeout-minutes: 60 + env: + SERVER_PUBKEY: "pR56vDJZb9b3BL3ZvCXIvgK0r2vCk7FiZ1RjeEhJVyU=" strategy: matrix: os: From e1b39b928c0a2e56e3d75e2958706b48c98a6a0f Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 9 Jul 2024 23:14:31 +0000 Subject: [PATCH 121/141] typo --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 41535c725..a848b6366 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -36,7 +36,7 @@ jobs: runs-on: ${{ matrix.os }} timeout-minutes: 60 env: - SERVER_PUBKEY: "pR56vDJZb9b3BL3ZvCXIvgK0r2vCk7FiZ1RjeEhJVyU=" + IMIX_SERVER_PUBKEY: "pR56vDJZb9b3BL3ZvCXIvgK0r2vCk7FiZ1RjeEhJVyU=" strategy: matrix: os: From f709426a8a037ab1cd06decd64939c78251c3271 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 9 Jul 2024 23:15:43 +0000 Subject: [PATCH 122/141] Let test cleanup temp files --- tavern/internal/secrets/debug_file_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tavern/internal/secrets/debug_file_test.go b/tavern/internal/secrets/debug_file_test.go index 167f12eb9..92a6ff674 100644 --- a/tavern/internal/secrets/debug_file_test.go +++ b/tavern/internal/secrets/debug_file_test.go @@ -31,7 +31,6 @@ secrets: func TestGetSecretsFile(t *testing.T) { path := createTestSecrets(t) - defer os.Remove(path) secretsManager, err := secrets.NewDebugFileSecrets(path) assert.Nil(t, err) @@ -46,7 +45,6 @@ func TestGetSecretsFile(t *testing.T) { func TestSetSecretsAddFile(t *testing.T) { path := createTestSecrets(t) - defer os.Remove(path) secretsManager, err := secrets.NewDebugFileSecrets(path) assert.Nil(t, err) @@ -78,8 +76,6 @@ func TestSetSecretsAddFile(t *testing.T) { func TestSetSecretsNewFile(t *testing.T) { tmpDir := t.TempDir() path := path.Join(tmpDir, "secrets.yaml") - defer os.Remove(path) - // path = "/tmp/test-secrets.yaml" secretsManager, err := secrets.NewDebugFileSecrets(path) assert.Nil(t, err) From 11cc7ce03abc9748d2443486b5d7a6aede16cc47 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 9 Jul 2024 23:34:42 +0000 Subject: [PATCH 123/141] defer close --- tavern/internal/secrets/debug_file.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tavern/internal/secrets/debug_file.go b/tavern/internal/secrets/debug_file.go index a988eee3d..076c84040 100644 --- a/tavern/internal/secrets/debug_file.go +++ b/tavern/internal/secrets/debug_file.go @@ -112,6 +112,7 @@ func (s DebugFileSecrets) setYamlStruct(path string, secrets Secrets) error { log.Printf("[ERROR] Failed to open secrets file %s: %v", path, err) return err } + defer file.Close() _, err = file.Write(data) if err != nil { @@ -128,6 +129,7 @@ func (s DebugFileSecrets) getYamlStruct(path string) (Secrets, error) { log.Printf("[ERROR] Failed to open secrets file %s: %v", path, err) return Secrets{}, err } + defer file.Close() data := make([]byte, MAX_FILE_SIZE) n, err := file.Read(data) @@ -168,9 +170,3 @@ func (s DebugFileSecrets) ensureSecretsFileExist() (string, error) { } return s.Path, nil } - -// func checkFileExists(filePath string) bool { -// _, error := os.Stat(filePath) -// //return !os.IsNotExist(err) -// return !errors.Is(error, os.ErrNotExist) -// } From e11f75236733c3ced9aaf84c069de9bbd2dd890a Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Tue, 9 Jul 2024 23:47:35 +0000 Subject: [PATCH 124/141] Test using tempdir --- tavern/main_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tavern/main_test.go b/tavern/main_test.go index 48517e870..809ae7ffc 100644 --- a/tavern/main_test.go +++ b/tavern/main_test.go @@ -2,18 +2,22 @@ package main import ( "os" + "path" "testing" ) // TestMainFunc runs main after configuring the application to immediately exit. // This validates our default configurations are successful. func TestMainFunc(t *testing.T) { + tmpDir := t.TempDir() + path := path.Join(tmpDir, "secrets.yaml") + os.Setenv(EnvEnableTestRunAndExit.Key, "1") os.Setenv(EnvHTTPListenAddr.Key, "127.0.0.1:8080") os.Setenv(EnvHTTPMetricsListenAddr.Key, "127.0.0.1:8081") os.Setenv(EnvEnablePProf.Key, "1") os.Setenv(EnvEnableMetrics.Key, "1") - os.Setenv(EnvSecretsManagerPath.Key, "/tmp/test-secret.yml") + os.Setenv(EnvSecretsManagerPath.Key, path) defer func() { unsetList := []string{ EnvEnableTestRunAndExit.Key, From 89e386536d67896089258c91d1b503f739bcac52 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 10 Jul 2024 00:53:54 +0000 Subject: [PATCH 125/141] Resolve feedback --- docs/_docs/user-guide/imix.md | 10 ++++++---- tavern/app.go | 2 +- tavern/internal/secrets/gcp.go | 3 +-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/_docs/user-guide/imix.md b/docs/_docs/user-guide/imix.md index 6159b0c5f..8793d2418 100644 --- a/docs/_docs/user-guide/imix.md +++ b/docs/_docs/user-guide/imix.md @@ -77,6 +77,8 @@ This isn't ideal as in the UI each new beacon will appear as thought it were on **We strongly recommend building agents inside the provided devcontainer `.devcontainer`** Building in the dev container limits variables that might cause issues and is the most tested way to compile. +**Imix requires a server public key so it can encrypt messsages to and from the server check the server log for `[INFO] Public key: `** + ### Linux ```bash @@ -86,7 +88,7 @@ sudo apt update sudo apt install musl-tools cd realm/implants/imix/ -RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --target=x86_64-unknown-linux-musl +IMIX_SERVER_PUBKEY="" RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --target=x86_64-unknown-linux-musl ``` ### MacOS @@ -110,9 +112,9 @@ sudo apt install gcc-mingw-w64 cd realm/implants/imix/ # Build imix.exe -RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --target=x86_64-pc-windows-gnu +IMIX_SERVER_PUBKEY="" RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --target=x86_64-pc-windows-gnu # Build imix.svc.exe -RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --features win_service --target=x86_64-pc-windows-gnu +IMIX_SERVER_PUBKEY="" RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --features win_service --target=x86_64-pc-windows-gnu # Build imix.dll -RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --lib --target=x86_64-pc-windows-gnu +IMIX_SERVER_PUBKEY="" RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --lib --target=x86_64-pc-windows-gnu ``` diff --git a/tavern/app.go b/tavern/app.go index 9efa86933..3e0b28539 100644 --- a/tavern/app.go +++ b/tavern/app.go @@ -355,7 +355,7 @@ func getKeyPair() (*ecdh.PublicKey, *ecdh.PrivateKey) { priv_key_bytes, err := x509.MarshalPKCS8PrivateKey(priv_key) if err != nil { - log.Printf("[ERROR] Unable to set marshal priv key: %v", err) + log.Printf("[ERROR] Unable to marshal private key: %v", err) return nil, nil } _, err = secretsManager.SetValue("tavern_encryption_private_key", priv_key_bytes) diff --git a/tavern/internal/secrets/gcp.go b/tavern/internal/secrets/gcp.go index f9b894cb2..54c05d7a6 100644 --- a/tavern/internal/secrets/gcp.go +++ b/tavern/internal/secrets/gcp.go @@ -29,7 +29,6 @@ func (g Gcp) GetName() string { // GetValue implements SecretsManager. func (g Gcp) GetValue(key string) ([]byte, error) { - // name := "projects/my-project/secrets/my-secret" name := fmt.Sprintf("projects/%s/secrets/%s_%s/versions/latest", g.projectID, g.prefix, key) // Build the request. @@ -109,11 +108,11 @@ func (g Gcp) SetValue(key string, value []byte) ([]byte, error) { } func NewGcp(projectID string) (SecretsManager, error) { - // GCP project in which to store secrets in Secret Manager. ctx := context.Background() // If unset try to figure out the current GCP if projectID == "" { + // GCP project in which to store secrets in Secret Manager. tmp, err := GetCurrentGcpProject(ctx) projectID = tmp if err != nil { From 84033260c0ec11eb1ba0e0cb0f2ea68d8b6859db Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Thu, 11 Jul 2024 22:36:47 +0000 Subject: [PATCH 126/141] Cleanup. --- tavern/internal/cryptocodec/cryptocodec.go | 82 +++++++++++++++------- 1 file changed, 55 insertions(+), 27 deletions(-) diff --git a/tavern/internal/cryptocodec/cryptocodec.go b/tavern/internal/cryptocodec/cryptocodec.go index ae97f4197..71607c230 100644 --- a/tavern/internal/cryptocodec/cryptocodec.go +++ b/tavern/internal/cryptocodec/cryptocodec.go @@ -16,9 +16,37 @@ import ( ) // TODO: Switch to a gomap and mutex. -var session_pub_keys = sync.Map{} +var session_pub_keys = NewSyncMap() -// TODO: Should we make this a random long byte array in case it gets used anywhere to avoid encrypting data with a week key? - Sliver handles errors in this way. +type SyncMap struct { + Mutex sync.RWMutex // Read Write Mutex to allow for multiple readers + Map map[int][]byte // Example data map +} + +func NewSyncMap() *SyncMap { + return &SyncMap{Mutex: sync.RWMutex{}, Map: make(map[int][]byte)} +} + +func (s *SyncMap) Load(key int) ([]byte, bool) { + defer s.Mutex.Unlock() + s.Mutex.Lock() + res, ok := s.Map[key] + return res, ok +} + +func (s *SyncMap) Store(key int, value []byte) { + defer s.Mutex.Unlock() + s.Mutex.Lock() + s.Map[key] = value +} + +func (s *SyncMap) Delete(key int) { + defer s.Mutex.Unlock() + s.Mutex.Lock() + delete(s.Map, key) +} + +// TODO: Should we make this a random long byte array in case it gets used anywhere to avoid encrypting data with a weak key? - Sliver handles errors in this way. var FAILURE_BYTES = []byte{} func init() { @@ -53,7 +81,9 @@ func (s StreamDecryptCodec) Unmarshal(buf []byte, v any) error { return err } dec_buf, pub_key := s.Csvc.Decrypt(buf) - s.Csvc.SetAgentPubkey(pub_key) + + session_pub_keys.Store(id, pub_key) + proto := encoding.GetCodec("proto") return proto.Unmarshal(dec_buf, v) } @@ -73,27 +103,6 @@ func NewCryptoSvc(priv_key *ecdh.PrivateKey) CryptoSvc { } } -func (csvc *CryptoSvc) GetAgentPubkey() []byte { - id, err := goid() - if err != nil { - log.Println("[ERROR] Unable to find GOID ", id) - return FAILURE_BYTES - } - res, ok := session_pub_keys.Load(id) - if !ok { - log.Println("[ERROR] Public key not found") - } - return res.([]byte) -} - -func (csvc *CryptoSvc) SetAgentPubkey(client_pub_key []byte) { - id, err := goid() - if err != nil { - log.Println("[ERROR] Failed to get goid") - } - session_pub_keys.Store(id, client_pub_key) -} - func (csvc *CryptoSvc) generate_shared_key(client_pub_key_bytes []byte) []byte { x22519_curve := ecdh.X25519() client_pub_key, err := x22519_curve.NewPublicKey(client_pub_key_bytes) @@ -119,7 +128,13 @@ func (csvc *CryptoSvc) Decrypt(in_arr []byte) ([]byte, []byte) { } client_pub_key_bytes := in_arr[:x25519.Size] - csvc.SetAgentPubkey(client_pub_key_bytes) + + id, err := goid() + if err != nil { + log.Println("[ERROR] Failed to get goid") + return FAILURE_BYTES, FAILURE_BYTES + } + session_pub_keys.Store(id, client_pub_key_bytes) // Generate shared secret derived_key := csvc.generate_shared_key(client_pub_key_bytes) @@ -133,7 +148,7 @@ func (csvc *CryptoSvc) Decrypt(in_arr []byte) ([]byte, []byte) { // Progress in_arr buf in_arr = in_arr[x25519.Size:] - // Read nonce + // Read nonce & cipher text if len(in_arr) < aead.NonceSize() { log.Printf("[ERROR] Input bytes to short %d expected at least %d\n", len(in_arr), aead.NonceSize()) return FAILURE_BYTES, FAILURE_BYTES @@ -153,7 +168,20 @@ func (csvc *CryptoSvc) Decrypt(in_arr []byte) ([]byte, []byte) { // TODO: Don't use [] ref. func (csvc *CryptoSvc) Encrypt(in_arr []byte) []byte { // Get the client pub key? - client_pub_key_bytes := csvc.GetAgentPubkey() + id, err := goid() + if err != nil { + log.Println("[ERROR] Unable to find GOID ", id) + return FAILURE_BYTES + } + + client_pub_key_bytes, ok := session_pub_keys.Load(id) + if !ok { + log.Println("[ERROR] Public key not found") + return FAILURE_BYTES + } + + // We should only need to use these once so delete it after use + session_pub_keys.Delete(id) // Generate shared secret shared_key := csvc.generate_shared_key(client_pub_key_bytes) From b551d14c7b8208e9974df51bcf15351828f67010 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Thu, 11 Jul 2024 22:49:59 +0000 Subject: [PATCH 127/141] hhhh --- implants/lib/pb/src/xchacha.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index 720d506d0..49c3db98a 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -40,6 +40,10 @@ fn get_key(pub_key: [u8; 32]) -> Result<[u8; 32]> { Ok(res) } +fn del_key(pub_key: [u8; 32]) -> Option<([u8; 32], [u8; 32])> { + key_history().lock().unwrap().remove_entry(&pub_key) +} + // ------------ #[derive(Debug, Clone, Default)] @@ -189,6 +193,9 @@ where let client_public_bytes = tmp_client_public_bytes.try_into().unwrap(); // Bruh idk how to not unwrap this :sob: let client_private_bytes = get_key(client_public_bytes).map_err(from_anyhow_error)?; + // Shouldn't need private key again once the message has been decrypted + del_key(client_public_bytes); + let cipher = chacha20poly1305::XChaCha20Poly1305::new(GenericArray::from_slice( &client_private_bytes, )); From c76cd1030613596a4c243a695dbb4d9608ceb6b8 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Fri, 12 Jul 2024 00:00:04 +0000 Subject: [PATCH 128/141] Cleanup --- implants/lib/pb/src/xchacha.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index 49c3db98a..0e02dae8e 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -17,8 +17,9 @@ use tonic::{ }; use x25519_dalek::{EphemeralSecret, PublicKey}; -const SERVER_PUBKEY_STR: &str = env!("IMIX_SERVER_PUBKEY"); -const SERVER_PUBKEY: [u8; 32] = const_decode::Base64.decode(SERVER_PUBKEY_STR.as_bytes()); +/* Compile-time constant for the server pubkey, derived from the IMIX_SERVER_PUBKEY environment variable during compilation. + */ +static SERVER_PUBKEY: [u8; 32] = const_decode::Base64.decode(env!("IMIX_SERVER_PUBKEY").as_bytes()); // ------------ From 7b089beccc7a84a9869800e618bdd86b332a0bc2 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Fri, 12 Jul 2024 00:01:35 +0000 Subject: [PATCH 129/141] Comments --- implants/lib/pb/src/xchacha.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index 0e02dae8e..3c0d48e7f 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -18,6 +18,7 @@ use tonic::{ use x25519_dalek::{EphemeralSecret, PublicKey}; /* Compile-time constant for the server pubkey, derived from the IMIX_SERVER_PUBKEY environment variable during compilation. + * To find the servers pubkey check the startup messages on the server look for `[INFO] Public key: ` */ static SERVER_PUBKEY: [u8; 32] = const_decode::Base64.decode(env!("IMIX_SERVER_PUBKEY").as_bytes()); From b055cefb7a7718f67122c9182cb67d1ff29839db Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 5 May 2025 01:24:27 +0000 Subject: [PATCH 130/141] Resolve merge conflicts --- docs/_docs/admin-guide/tavern.md | 9 + go.mod | 116 +++------- go.sum | 372 ++++++++----------------------- tavern/app.go | 11 +- 4 files changed, 133 insertions(+), 375 deletions(-) diff --git a/docs/_docs/admin-guide/tavern.md b/docs/_docs/admin-guide/tavern.md index 563af380d..2dd23ff29 100644 --- a/docs/_docs/admin-guide/tavern.md +++ b/docs/_docs/admin-guide/tavern.md @@ -117,6 +117,15 @@ By default, Tavern does not export metrics. You may use the below environment co | ENABLE_METRICS | Set to any value to enable the "/metrics" endpoint. | Disabled | No | | HTTP_METRICS_LISTEN_ADDR | Listen address for the metrics HTTP server, it must be different than the value of `HTTP_LISTEN_ADDR`. | `127.0.0.1:8080` | No | +### Secrets + +By default, Tavern wants to use a GCP KMS for secrets management. The secrets engine is used to generate keypairs when communicating with agents. +If you're running locally make suer to set the secrets manager to a local file path using: + +```bash +SECRETS_FILE_PATH="/tmp/secrets" go run ./tavern/ +``` + ### MySQL By default, Tavern operates an in-memory SQLite database. To persist data, a MySQL backend is supported. In order to configure Tavern to use MySQL, the `MYSQL_ADDR` environment variable must be set to the `host[:port]` of the database (e.g. `127.0.0.1`, `mydb.com`, or `mydb.com:3306`). You can reference the [mysql.Config](https://pkg.go.dev/github.com/go-sql-driver/mysql#Config) for additional information about Tavern's MySQL configuration. diff --git a/go.mod b/go.mod index e1a9bbb9f..91f809d6f 100644 --- a/go.mod +++ b/go.mod @@ -4,61 +4,39 @@ go 1.23.4 require ( cloud.google.com/go/pubsub v1.45.3 + cloud.google.com/go/secretmanager v1.14.2 entgo.io/contrib v0.6.0 entgo.io/ent v0.14.1 github.com/99designs/gqlgen v0.17.62 + github.com/cloudflare/circl v1.5.0 github.com/go-sql-driver/mysql v1.8.1 github.com/golang-jwt/jwt v3.2.2+incompatible github.com/google/go-cmp v0.6.0 github.com/hashicorp/go-multierror v1.1.1 -<<<<<<< HEAD github.com/mattn/go-sqlite3 v1.14.16 - github.com/prometheus/client_golang v1.18.0 - github.com/stretchr/testify v1.9.0 - github.com/urfave/cli v1.22.5 - github.com/vektah/gqlparser/v2 v2.5.10 - golang.org/x/crypto v0.24.0 - golang.org/x/net v0.26.0 - golang.org/x/oauth2 v0.21.0 - golang.org/x/sync v0.7.0 - google.golang.org/grpc v1.64.0 - google.golang.org/protobuf v1.34.2 -======= - github.com/mattn/go-sqlite3 v1.14.24 - github.com/prometheus/client_golang v1.20.5 + github.com/prometheus/client_golang v1.20.4 github.com/stretchr/testify v1.10.0 - github.com/urfave/cli v1.22.16 + github.com/urfave/cli v1.22.5 github.com/vektah/gqlparser/v2 v2.5.21 golang.org/x/crypto v0.31.0 golang.org/x/net v0.33.0 - golang.org/x/oauth2 v0.25.0 + golang.org/x/oauth2 v0.24.0 golang.org/x/sync v0.10.0 - google.golang.org/grpc v1.69.2 + google.golang.org/api v0.210.0 + google.golang.org/grpc v1.67.1 google.golang.org/protobuf v1.36.1 ->>>>>>> main gopkg.in/yaml.v3 v3.0.1 ) require ( -<<<<<<< HEAD - cloud.google.com/go/auth v0.6.1 // indirect - cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect - cloud.google.com/go/iam v1.1.9 // indirect - cloud.google.com/go/pubsub v1.40.0 // indirect - cloud.google.com/go/secretmanager v1.13.3 // indirect - dario.cat/mergo v1.0.0 // indirect -======= - cloud.google.com/go v0.117.0 // indirect - cloud.google.com/go/auth v0.13.0 // indirect + cloud.google.com/go v0.116.0 // indirect + cloud.google.com/go/auth v0.11.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect - cloud.google.com/go/iam v1.3.1 // indirect - dario.cat/mergo v1.0.1 // indirect ->>>>>>> main + cloud.google.com/go/iam v1.2.2 // indirect + dario.cat/mergo v1.0.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/ProtonMail/go-crypto v1.1.3 // indirect - github.com/bmatcuk/doublestar v1.3.4 // indirect - github.com/cloudflare/circl v1.5.0 // indirect github.com/cyphar/filepath-securejoin v0.3.6 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -70,13 +48,8 @@ require ( github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/google/s2a-go v0.1.8 // indirect github.com/google/wire v0.6.0 // indirect -<<<<<<< HEAD - github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.5 // indirect -======= github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect - github.com/googleapis/gax-go/v2 v2.14.1 // indirect ->>>>>>> main + github.com/googleapis/gax-go/v2 v2.14.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/klauspost/compress v1.17.11 // indirect @@ -87,42 +60,21 @@ require ( github.com/skeema/knownhosts v1.3.0 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect go.opencensus.io v0.24.0 // indirect -<<<<<<< HEAD - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect - golang.org/x/time v0.5.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect + go.opentelemetry.io/otel v1.29.0 // indirect + go.opentelemetry.io/otel/metric v1.29.0 // indirect + go.opentelemetry.io/otel/trace v1.29.0 // indirect + golang.org/x/time v0.8.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect - google.golang.org/api v0.187.0 // indirect - google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240624140628-dc46fd24d27d // indirect -======= - go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect - go.opentelemetry.io/otel v1.33.0 // indirect - go.opentelemetry.io/otel/metric v1.33.0 // indirect - go.opentelemetry.io/otel/trace v1.33.0 // indirect - golang.org/x/time v0.9.0 // indirect - golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect - google.golang.org/api v0.214.0 // indirect - google.golang.org/genproto v0.0.0-20250102185135-69823020774d // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d // indirect ->>>>>>> main + google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20241113202542-65e8d215514f // indirect gopkg.in/warnings.v0 v0.1.2 // indirect ) require ( -<<<<<<< HEAD - ariga.io/atlas v0.14.2 // indirect - cloud.google.com/go/compute v1.27.1 // indirect - cloud.google.com/go/compute/metadata v0.3.0 // indirect -======= - ariga.io/atlas v0.29.1 // indirect - cloud.google.com/go/compute/metadata v0.6.0 // indirect ->>>>>>> main + ariga.io/atlas v0.25.1-0.20240717145915-af51d3945208 // indirect + cloud.google.com/go/compute/metadata v0.5.2 // indirect github.com/agext/levenshtein v1.2.3 // indirect github.com/agnivade/levenshtein v1.2.0 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect @@ -146,24 +98,12 @@ require ( github.com/sosodev/duration v1.3.1 // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect -<<<<<<< HEAD - github.com/zclconf/go-cty v1.14.1 // indirect + github.com/zclconf/go-cty v1.14.4 // indirect gocloud.dev v0.37.0 - golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/sys v0.21.0 // indirect - golang.org/x/text v0.16.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect - google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d // indirect -======= - github.com/zclconf/go-cty v1.16.0 // indirect - gocloud.dev v0.40.0 - golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329 - golang.org/x/mod v0.22.0 // indirect - golang.org/x/sys v0.29.0 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 + golang.org/x/mod v0.20.0 // indirect + golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect - golang.org/x/tools v0.28.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect ->>>>>>> main + golang.org/x/tools v0.24.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 // indirect ) diff --git a/go.sum b/go.sum index 0ab4902c4..651701329 100644 --- a/go.sum +++ b/go.sum @@ -1,73 +1,35 @@ -ariga.io/atlas v0.29.1 h1:7gB8XRFTnJeZ7ZiccNCJqwBtUv3yjFyxRFDMzu0AmRg= -ariga.io/atlas v0.29.1/go.mod h1:lkLAw/t2/P7g5CFYlYmHvNuShlmGujwm3OGsW00xowI= +ariga.io/atlas v0.25.1-0.20240717145915-af51d3945208 h1:ixs1c/fAXGS3mTdalyKQrtvfkFjgChih/unX66YTzYk= +ariga.io/atlas v0.25.1-0.20240717145915-af51d3945208/go.mod h1:KPLc7Zj+nzoXfWshrcY1RwlOh94dsATQEy4UPrF2RkM= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -<<<<<<< HEAD -cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= -cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14= -cloud.google.com/go/auth v0.6.1 h1:T0Zw1XM5c1GlpN2HYr2s+m3vr1p2wy+8VN+Z1FKxW38= -cloud.google.com/go/auth v0.6.1/go.mod h1:eFHG7zDzbXHKmjJddFG/rBlcGp6t25SwRUiEQSlO4x4= -cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4= -cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= -cloud.google.com/go/compute v1.25.0 h1:H1/4SqSUhjPFE7L5ddzHOfY2bCAvjwNRZPNl6Ni5oYU= -cloud.google.com/go/compute v1.25.0/go.mod h1:GR7F0ZPZH8EhChlMo9FkLd7eUTwEymjqQagxzilIxIE= -cloud.google.com/go/compute v1.27.0 h1:EGawh2RUnfHT5g8f/FX3Ds6KZuIBC77hZoDrBvEZw94= -cloud.google.com/go/compute v1.27.0/go.mod h1:LG5HwRmWFKM2C5XxHRiNzkLLXW48WwvyVC0mfWsYPOM= -cloud.google.com/go/compute v1.27.1 h1:0WbBLIPNANheCRZ4h8QhgzjN53KMutbiVBOLtPiVzBU= -cloud.google.com/go/compute v1.27.1/go.mod h1:UVWm+bWKEKoM+PW2sZycP1Jgk3NhKwR2Iy2Cnp/G40I= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= -cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= -cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= -cloud.google.com/go/iam v1.1.8 h1:r7umDwhj+BQyz0ScZMp4QrGXjSTI3ZINnpgU2nlB/K0= -cloud.google.com/go/iam v1.1.8/go.mod h1:GvE6lyMmfxXauzNq8NbgJbeVQNspG+tcdL/W8QO1+zE= -cloud.google.com/go/iam v1.1.9 h1:oSkYLVtVme29uGYrOcKcvJRht7cHJpYD09GM9JaR0TE= -cloud.google.com/go/iam v1.1.9/go.mod h1:Nt1eDWNYH9nGQg3d/mY7U1hvfGmsaG9o/kLGoLoLXjQ= -cloud.google.com/go/pubsub v1.37.0 h1:0uEEfaB1VIJzabPpwpZf44zWAKAme3zwKKxHk7vJQxQ= -cloud.google.com/go/pubsub v1.37.0/go.mod h1:YQOQr1uiUM092EXwKs56OPT650nwnawc+8/IjoUeGzQ= -cloud.google.com/go/pubsub v1.39.0 h1:qt1+S6H+wwW8Q/YvDwM8lJnq+iIFgFEgaD/7h3lMsAI= -cloud.google.com/go/pubsub v1.39.0/go.mod h1:FrEnrSGU6L0Kh3iBaAbIUM8KMR7LqyEkMboVxGXCT+s= -cloud.google.com/go/pubsub v1.40.0 h1:0LdP+zj5XaPAGtWr2V6r88VXJlmtaB/+fde1q3TU8M0= -cloud.google.com/go/pubsub v1.40.0/go.mod h1:BVJI4sI2FyXp36KFKvFwcfDRDfR8MiLT8mMhmIhdAeA= -cloud.google.com/go/secretmanager v1.13.3 h1:VqUVYY3U6uFXOhPdZgAoZH9m8E6p7eK02TsDRj2SBf4= -cloud.google.com/go/secretmanager v1.13.3/go.mod h1:e45+CxK0w6GaL4hS+KabgQskl4RdSS30b+HRf0TH0kk= -dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= -dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= -entgo.io/contrib v0.4.5 h1:BFaOHwFLE8WZjVJadP0XHCIaxgcC1BAtUvAyw7M/GHk= -entgo.io/contrib v0.4.5/go.mod h1:wpZyq2DJgthugFvDBlaqMXj9mV4/9ebyGEn7xlTVQqE= -entgo.io/ent v0.12.4 h1:LddPnAyxls/O7DTXZvUGDj0NZIdGSu317+aoNLJWbD8= -entgo.io/ent v0.12.4/go.mod h1:Y3JVAjtlIk8xVZYSn3t3mf8xlZIn5SAOXZQxD6kKI+Q= -======= -cloud.google.com/go v0.117.0 h1:Z5TNFfQxj7WG2FgOGX1ekC5RiXrYgms6QscOm32M/4s= -cloud.google.com/go v0.117.0/go.mod h1:ZbwhVTb1DBGt2Iwb3tNO6SEK4q+cplHZmLWH+DelYYc= -cloud.google.com/go/auth v0.13.0 h1:8Fu8TZy167JkW8Tj3q7dIkr2v4cndv41ouecJx0PAHs= -cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q= +cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= +cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= +cloud.google.com/go/auth v0.11.0 h1:Ic5SZz2lsvbYcWT5dfjNWgw6tTlGi2Wc8hyQSC9BstA= +cloud.google.com/go/auth v0.11.0/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI= cloud.google.com/go/auth/oauth2adapt v0.2.6 h1:V6a6XDu2lTwPZWOawrAa9HUK+DB2zfJyTuciBG5hFkU= cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8= -cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= -cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= -cloud.google.com/go/iam v1.3.1 h1:KFf8SaT71yYq+sQtRISn90Gyhyf4X8RGgeAVC8XGf3E= -cloud.google.com/go/iam v1.3.1/go.mod h1:3wMtuyT4NcbnYNPLMBzYRFiEfjKfJlLVLrisE7bwm34= -cloud.google.com/go/kms v1.20.3 h1:a61yIN5LN8ozWxOC6tjUx5V5SEzfkS+b69kYMQfzGzE= -cloud.google.com/go/kms v1.20.3/go.mod h1:YvX+xhp2E2Sc3vol5IcRlBhH14Ecl3kegUY/DtH7EWQ= -cloud.google.com/go/longrunning v0.6.3 h1:A2q2vuyXysRcwzqDpMMLSI6mb6o39miS52UEG/Rd2ng= -cloud.google.com/go/longrunning v0.6.3/go.mod h1:k/vIs83RN4bE3YCswdXC5PFfWVILjm3hpEUlSko4PiI= +cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo= +cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= +cloud.google.com/go/iam v1.2.2 h1:ozUSofHUGf/F4tCNy/mu9tHLTaxZFLOUiKzjcgWHGIA= +cloud.google.com/go/iam v1.2.2/go.mod h1:0Ys8ccaZHdI1dEUilwzqng/6ps2YB6vRsjIe00/+6JY= +cloud.google.com/go/kms v1.20.1 h1:og29Wv59uf2FVaZlesaiDAqHFzHaoUyHI3HYp9VUHVg= +cloud.google.com/go/kms v1.20.1/go.mod h1:LywpNiVCvzYNJWS9JUcGJSVTNSwPwi0vBAotzDqn2nc= +cloud.google.com/go/longrunning v0.6.2 h1:xjDfh1pQcWPEvnfjZmwjKQEcHnpz6lHjfy7Fo0MK+hc= +cloud.google.com/go/longrunning v0.6.2/go.mod h1:k/vIs83RN4bE3YCswdXC5PFfWVILjm3hpEUlSko4PiI= cloud.google.com/go/pubsub v1.45.3 h1:prYj8EEAAAwkp6WNoGTE4ahe0DgHoyJd5Pbop931zow= cloud.google.com/go/pubsub v1.45.3/go.mod h1:cGyloK/hXC4at7smAtxFnXprKEFTqmMXNNd9w+bd94Q= -dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= -dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +cloud.google.com/go/secretmanager v1.14.2 h1:2XscWCfy//l/qF96YE18/oUaNJynAx749Jg3u0CjQr8= +cloud.google.com/go/secretmanager v1.14.2/go.mod h1:Q18wAPMM6RXLC/zVpWTlqq2IBSbbm7pKBlM3lCKsmjw= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= entgo.io/contrib v0.6.0 h1:xfo4TbJE7sJZWx7BV7YrpSz7IPFvS8MzL3fnfzZjKvQ= entgo.io/contrib v0.6.0/go.mod h1:3qWIseJ/9Wx2Hu5zVh15FDzv7d/UvKNcYKdViywWCQg= entgo.io/ent v0.14.1 h1:fUERL506Pqr92EPHJqr8EYxbPioflJo6PudkrEA8a/s= entgo.io/ent v0.14.1/go.mod h1:MH6XLG0KXpkcDQhKiHfANZSzR55TJyPL5IGNpI8wpco= ->>>>>>> main filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/99designs/gqlgen v0.17.62 h1:Wovt1+XJN9dTWYh92537Y9a5FuMVSkrQL4bn0a8v5Rg= github.com/99designs/gqlgen v0.17.62/go.mod h1:sVCM2iwIZisJjTI/DEC3fpH+HFgxY1496ZJ+jbT9IjA= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= @@ -93,38 +55,36 @@ github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= -github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= -github.com/aws/aws-sdk-go-v2 v1.30.3 h1:jUeBtG0Ih+ZIFH0F4UkmL9w3cSpaMv9tYYDbzILP8dY= -github.com/aws/aws-sdk-go-v2 v1.30.3/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc= -github.com/aws/aws-sdk-go-v2/config v1.27.27 h1:HdqgGt1OAP0HkEDDShEl0oSYa9ZZBSOmKpdpsDMdO90= -github.com/aws/aws-sdk-go-v2/config v1.27.27/go.mod h1:MVYamCg76dFNINkZFu4n4RjDixhVr51HLj4ErWzrVwg= -github.com/aws/aws-sdk-go-v2/credentials v1.17.27 h1:2raNba6gr2IfA0eqqiP2XiQ0UVOpGPgDSi0I9iAP+UI= -github.com/aws/aws-sdk-go-v2/credentials v1.17.27/go.mod h1:gniiwbGahQByxan6YjQUMcW4Aov6bLC3m+evgcoN4r4= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 h1:KreluoV8FZDEtI6Co2xuNk/UqI9iwMrOx/87PBNIKqw= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11/go.mod h1:SeSUYBLsMYFoRvHE0Tjvn7kbxaUhl75CJi1sbfhMxkU= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 h1:SoNJ4RlFEQEbtDcCEt+QG56MY4fm4W8rYirAmq+/DdU= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15/go.mod h1:U9ke74k1n2bf+RIgoX1SXFed1HLs51OgUSs+Ph0KJP8= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 h1:C6WHdGnTDIYETAm5iErQUiVNsclNx9qbJVPIt03B6bI= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15/go.mod h1:ZQLZqhcu+JhSrA9/NXRm8SkDvsycE+JkV3WGY41e+IM= +github.com/aws/aws-sdk-go v1.50.36 h1:PjWXHwZPuTLMR1NIb8nEjLucZBMzmf84TLoLbD8BZqk= +github.com/aws/aws-sdk-go v1.50.36/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go-v2 v1.25.3 h1:xYiLpZTQs1mzvz5PaI6uR0Wh57ippuEthxS4iK5v0n0= +github.com/aws/aws-sdk-go-v2 v1.25.3/go.mod h1:35hUlJVYd+M++iLI3ALmVwMOyRYMmRqUXpTtRGW+K9I= +github.com/aws/aws-sdk-go-v2/config v1.27.7 h1:JSfb5nOQF01iOgxFI5OIKWwDiEXWTyTgg1Mm1mHi0A4= +github.com/aws/aws-sdk-go-v2/config v1.27.7/go.mod h1:PH0/cNpoMO+B04qET699o5W92Ca79fVtbUnvMIZro4I= +github.com/aws/aws-sdk-go-v2/credentials v1.17.7 h1:WJd+ubWKoBeRh7A5iNMnxEOs982SyVKOJD+K8HIezu4= +github.com/aws/aws-sdk-go-v2/credentials v1.17.7/go.mod h1:UQi7LMR0Vhvs+44w5ec8Q+VS+cd10cjwgHwiVkE0YGU= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.3 h1:p+y7FvkK2dxS+FEwRIDHDe//ZX+jDhP8HHE50ppj4iI= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.3/go.mod h1:/fYB+FZbDlwlAiynK9KDXlzZl3ANI9JkD0Uhz5FjNT4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.3 h1:ifbIbHZyGl1alsAhPIYsHOg5MuApgqOvVeI8wIugXfs= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.3/go.mod h1:oQZXg3c6SNeY6OZrDY+xHcF4VGIEoNotX2B4PrDeoJI= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.3 h1:Qvodo9gHG9F3E8SfYOspPeBt0bjSbsevK8WhRAUHcoY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.3/go.mod h1:vCKrdLXtybdf/uQd/YfVR2r5pcbNuEYKzMQpcxmeSJw= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 h1:HGErhhrxZlQ044RiM+WdoZxp0p+EGM62y3L6pwA4olE= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17/go.mod h1:RkZEx4l0EHYDJpWppMJ3nD9wZJAa8/0lq9aVC+r2UII= -github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 h1:BXx0ZIxvrJdSgSvKTZ+yRBeSqqgPM89VPlulEcl37tM= -github.com/aws/aws-sdk-go-v2/service/sso v1.22.4/go.mod h1:ooyCOXjvJEsUw7x+ZDHeISPMhtwI3ZCB7ggFMcFfWLU= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 h1:yiwVzJW2ZxZTurVbYWA7QOrAaCYQR72t0wrSBfoesUE= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4/go.mod h1:0oxfLkpz3rQ/CHlx5hB7H69YUpFiI1tql6Q6Ne+1bCw= -github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 h1:ZsDKRLXGWHk8WdtyYMoGNO7bTudrvuKpDKgMVRlepGE= -github.com/aws/aws-sdk-go-v2/service/sts v1.30.3/go.mod h1:zwySh8fpFyXp9yOr/KVzxOl8SRqgf/IDw5aUt9UKFcQ= -github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE= -github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 h1:EyBZibRTVAs6ECHZOw5/wlylS9OcTzwyjeQMudmREjE= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1/go.mod h1:JKpmtYhhPs7D97NL/ltqz7yCkERFW5dOlHyVl66ZYF8= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.5 h1:K/NXvIftOlX+oGgWGIa3jDyYLDNsdVhsjHmsBH2GLAQ= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.5/go.mod h1:cl9HGLV66EnCmMNzq4sYOti+/xo8w34CsgzVtm2GgsY= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.2 h1:XOPfar83RIRPEzfihnp+U6udOveKZJvPQ76SKWrLRHc= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.2/go.mod h1:Vv9Xyk1KMHXrR3vNQe8W5LMFdTjSeWk0gBZBzvf3Qa0= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.2 h1:pi0Skl6mNl2w8qWZXcdOyg197Zsf4G97U7Sso9JXGZE= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.2/go.mod h1:JYzLoEVeLXk+L4tn1+rrkfhkxl6mLDEVaDSvGq9og90= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.4 h1:Ppup1nVNAOWbBOrcoOxaxPeEnSFB2RnnQdguhXpmeQk= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.4/go.mod h1:+K1rNPVyGxkRuv9NNiaZ4YhBFuyw2MMA9SlIJ1Zlpz8= +github.com/aws/smithy-go v1.20.1 h1:4SZlSlMr36UEqC7XOyRVb27XMeZubNcBNN+9IgEPIQw= +github.com/aws/smithy-go v1.20.1/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0= -github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -132,7 +92,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys= github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM= @@ -201,8 +161,8 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-replayers/grpcreplay v1.3.0 h1:1Keyy0m1sIpqstQmgz307zhiJ1pV4uIlFds5weTmxbo= -github.com/google/go-replayers/grpcreplay v1.3.0/go.mod h1:v6NgKtkijC0d3e3RW8il6Sy5sqRVUwoQa4mHOGEy8DI= +github.com/google/go-replayers/grpcreplay v1.1.0 h1:S5+I3zYyZ+GQz68OfbURDdt/+cSMqCK1wrvNx7WBzTE= +github.com/google/go-replayers/grpcreplay v1.1.0/go.mod h1:qzAvJ8/wi57zq7gWqaE6AwLM6miiXUQwP1S+I9icmhk= github.com/google/go-replayers/httpreplay v1.2.0 h1:VM1wEyyjaoU53BwrOnaf9VhAyQQEEioJvFYxYcLRKzk= github.com/google/go-replayers/httpreplay v1.2.0/go.mod h1:WahEFFZZ7a1P4VM1qEeHy+tME4bwyqPcwWbNlUI1Mcg= github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= @@ -215,23 +175,12 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI= github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA= -<<<<<<< HEAD -github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= -github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= -github.com/googleapis/gax-go/v2 v2.12.2 h1:mhN09QQW1jEWeMF74zGR81R30z4VJzjZsfkUhuHF+DA= -github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= -github.com/googleapis/gax-go/v2 v2.12.5 h1:8gw9KZK8TiVKB6q3zHY3SBzLnrGp6HQjyfYBYGmXdxA= -github.com/googleapis/gax-go/v2 v2.12.5/go.mod h1:BUDKcWo+RaKq5SC9vVYL0wLADa3VcfswbOMMRmB9H3E= -github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= -github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= -======= github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= -github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q= -github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA= +github.com/googleapis/gax-go/v2 v2.14.0 h1:f+jMrjBPl+DL9nI4IQzLUxMq7XrAqFYB7hBPqMNIe8o= +github.com/googleapis/gax-go/v2 v2.14.0/go.mod h1:lhBCnjdLrWRaPvLWhmc8IS24m9mr07qSYnHncrgo+zk= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= ->>>>>>> main github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -258,8 +207,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= -github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY= @@ -274,8 +223,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= -github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI= +github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= @@ -283,12 +232,14 @@ github.com/prometheus/common v0.61.0 h1:3gv/GThfX0cV2lpO7gkTUwZru38mxevy90Bj8YFS github.com/prometheus/common v0.61.0/go.mod h1:zr29OCN/2BsJRaFwG8QOBr41D6kkchKbpeNH7pAjb/s= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= -github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY= github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M= @@ -298,102 +249,58 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -<<<<<<< HEAD -======= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= ->>>>>>> main github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -<<<<<<< HEAD -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU= -github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/vektah/gqlparser/v2 v2.5.10 h1:6zSM4azXC9u4Nxy5YmdmGu4uKamfwsdKTwp5zsEealU= -github.com/vektah/gqlparser/v2 v2.5.10/go.mod h1:1rCcfwB2ekJofmluGWXMSEnPMZgbxzwj6FaZ/4OT8Cc= -github.com/vmihailenco/msgpack/v5 v5.4.0 h1:hRM0digJwyR6vll33NNAwCFguy5JuBD6jxDmQP3l608= -github.com/vmihailenco/msgpack/v5 v5.4.0/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= -======= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ= -github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po= +github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU= +github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vektah/gqlparser/v2 v2.5.21 h1:Zw1rG2dr1pRR4wqwbVq4d6+xk2f4ut/yo+hwr4QjE08= github.com/vektah/gqlparser/v2 v2.5.21/go.mod h1:xMl+ta8a5M1Yo1A1Iwt/k7gSpscwSnHZdw7tfhEGfTM= github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= ->>>>>>> main github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zclconf/go-cty v1.16.0 h1:xPKEhst+BW5D0wxebMZkxgapvOE/dw7bFTlgSc9nD6w= -github.com/zclconf/go-cty v1.16.0/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= +github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8= +github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo= github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM= go.einride.tech/aip v0.68.0 h1:4seM66oLzTpz50u4K1zlJyOXQ3tCzcJN7I22tKkjipw= go.einride.tech/aip v0.68.0/go.mod h1:7y9FF8VtPWqpxuAxl0KQWqaULxW4zFIesD6zF5RIHHg= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -<<<<<<< HEAD -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= +go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= +go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= +go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= +go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= +go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo= +go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= +go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= +go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= gocloud.dev v0.37.0 h1:XF1rN6R0qZI/9DYjN16Uy0durAmSlf58DHOcb28GPro= gocloud.dev v0.37.0/go.mod h1:7/O4kqdInCNsc6LqgmuFnS0GRew4XNNYWpA44yQnwco= -======= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 h1:PS8wXpbyaDJQ2VDHHncMe9Vct0Zn1fEjpsjrLxGJoSc= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0/go.mod h1:HDBUsEjOuRC0EzKZ1bSaRGZWUBAzo+MhAcUUORSr4D0= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= -go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw= -go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I= -go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ= -go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M= -go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= -go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= -go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc= -go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= -go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= -go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= -gocloud.dev v0.40.0 h1:f8LgP+4WDqOG/RXoUcyLpeIAGOcAbZrZbDQCUee10ng= -gocloud.dev v0.40.0/go.mod h1:drz+VyYNBvrMTW0KZiBAYEdl8lbNZx+OQ7oQvdrFmSQ= ->>>>>>> main golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -<<<<<<< HEAD -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= -golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= -======= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= ->>>>>>> main golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329 h1:9kj3STMvgqy3YA4VQXBrN7925ICMxD5wzMRcgA30588= -golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -401,13 +308,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -<<<<<<< HEAD -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -======= -golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= -golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= ->>>>>>> main +golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= +golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -422,23 +324,11 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -<<<<<<< HEAD -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= -golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= -golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= -golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -======= golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70= -golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= ->>>>>>> main +golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= +golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -446,13 +336,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -<<<<<<< HEAD -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -======= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= ->>>>>>> main golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -469,28 +354,16 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -<<<<<<< HEAD -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -======= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= ->>>>>>> main +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -<<<<<<< HEAD -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= -======= golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= ->>>>>>> main golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -499,17 +372,10 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -<<<<<<< HEAD -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -======= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= -golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= ->>>>>>> main +golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= +golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -520,71 +386,32 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= -<<<<<<< HEAD -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= -google.golang.org/api v0.169.0 h1:QwWPy71FgMWqJN/l6jVlFHUa29a7dcUy02I8o799nPY= -google.golang.org/api v0.169.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg= -google.golang.org/api v0.187.0 h1:Mxs7VATVC2v7CY+7Xwm4ndkX71hpElcvx0D1Ji/p1eo= -google.golang.org/api v0.187.0/go.mod h1:KIHlTc4x7N7gKKuVsdmfBXN13yEEWXWFURWY6SBp2gk= -======= -golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= -golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= -golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= -google.golang.org/api v0.214.0 h1:h2Gkq07OYi6kusGOaT/9rnNljuXmqPnaig7WGPmKbwA= -google.golang.org/api v0.214.0/go.mod h1:bYPpLG8AyeMWwDU6NXoB00xC0DFkikVvd5MfwoxjLqE= ->>>>>>> main +google.golang.org/api v0.210.0 h1:HMNffZ57OoZCRYSbdWVRoqOa8V8NIHLL0CzdBPLztWk= +google.golang.org/api v0.210.0/go.mod h1:B9XDZGnx2NtyjzVkOVTGrFSAVZgPcbedzKg/gTLwqBs= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -<<<<<<< HEAD -google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 h1:ImUcDPHjTrAqNhlOkSocDLfG9rrNHH7w7uoKWPaWZ8s= -google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7/go.mod h1:/3XmxOjePkvmKrHuBy4zNFw7IzxJXtAgdpXi8Ll990U= -google.golang.org/genproto v0.0.0-20240624140628-dc46fd24d27d h1:PksQg4dV6Sem3/HkBX+Ltq8T0ke0PKIRBNBatoDTVls= -google.golang.org/genproto v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:s7iA721uChleev562UJO2OYB0PPT9CMFjV+Ce7VJH5M= -google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094 h1:6whtk83KtD3FkGrVb2hFXuQ+ZMbCNdakARIn/aHMmG8= -google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094/go.mod h1:Zs4wYw8z1zr6RNF4cwYb31mvN/EGaKAdQjNCF3DW6K4= -google.golang.org/genproto/googleapis/api v0.0.0-20240311173647-c811ad7063a7 h1:oqta3O3AnlWbmIE3bFnWbu4bRxZjfbWCp0cKSuZh01E= -google.golang.org/genproto/googleapis/api v0.0.0-20240311173647-c811ad7063a7/go.mod h1:VQW3tUculP/D4B+xVCo+VgSq8As6wA9ZjHl//pmk+6s= -google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4 h1:MuYw1wJzT+ZkybKfaOXKp5hJiZDn2iHaXRw0mRYdHSc= -google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4/go.mod h1:px9SlOOZBg1wM1zdnr8jEL4CNGUBZ+ZKYtNPApNQc4c= -google.golang.org/genproto/googleapis/api v0.0.0-20240624140628-dc46fd24d27d h1:Aqf0fiIdUQEj0Gn9mKFFXoQfTTEaNopWpfVyYADxiSg= -google.golang.org/genproto/googleapis/api v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:Od4k8V1LQSizPRUK4OzZ7TBE/20k+jPczUDAEyvn69Y= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240311173647-c811ad7063a7 h1:8EeVk1VKMD+GD/neyEHGmz7pFblqPjHoi+PGQIlLx2s= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240311173647-c811ad7063a7/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d h1:k3zyW3BYYR30e8v3x0bTDdE9vpYFjZHK+HcyqkrppWk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= -======= -google.golang.org/genproto v0.0.0-20250102185135-69823020774d h1:3NH+6ZtWWhXDpEJEAtzF1Gp/zA87pKkIB4gO1Ag8VSI= -google.golang.org/genproto v0.0.0-20250102185135-69823020774d/go.mod h1:zhXVSAeuPiprFfMSrt7Jo1Uighv2Nfu3HAZrw83tcYE= -google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA= -google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4= ->>>>>>> main +google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 h1:ToEetK57OidYuqD4Q5w+vfEnPvPpuTwedCNVohYJfNk= +google.golang.org/genproto v0.0.0-20241118233622-e639e219e697/go.mod h1:JJrvXBWRZaFMxBufik1a4RpFw4HhgVtBBWQeQgUj2cc= +google.golang.org/genproto/googleapis/api v0.0.0-20241113202542-65e8d215514f h1:M65LEviCfuZTfrfzwwEoxVtgvfkFkBUbFnRbxCXuXhU= +google.golang.org/genproto/googleapis/api v0.0.0-20241113202542-65e8d215514f/go.mod h1:Yo94eF2nj7igQt+TiJ49KxjIH8ndLYPZMIRSiRcEbg0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 h1:LWZqQOEjDyONlF1H6afSWpAL/znlREo2tHfLoe+8LMA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -<<<<<<< HEAD -google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= -google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= -======= -google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU= -google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= ->>>>>>> main +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -594,17 +421,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -<<<<<<< HEAD -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -======= google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= ->>>>>>> main gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/tavern/app.go b/tavern/app.go index d29ecf3d9..ed35d9361 100644 --- a/tavern/app.go +++ b/tavern/app.go @@ -7,7 +7,6 @@ import ( "crypto/rand" "crypto/x509" "encoding/base64" - "encoding/json" "fmt" "log" "log/slog" @@ -290,15 +289,6 @@ func newGraphQLHandler(client *ent.Client, repoImporter graphql.RepoImporter) ht srv := handler.NewDefaultServer(graphql.NewSchema(client, repoImporter)) srv.Use(entgql.Transactioner{TxOpener: client}) - // GraphQL Logging - gqlLogger := log.New(os.Stderr, "[GraphQL] ", log.Flags()) - srv.AroundOperations(func(ctx context.Context, next gqlgraphql.OperationHandler) gqlgraphql.ResponseHandler { - oc := gqlgraphql.GetOperationContext(ctx) - reqVars, err := json.Marshal(oc.Variables) - if err != nil { - gqlLogger.Printf("[ERROR] failed to marshal variables to JSON: %v\n", err) - return next(ctx) - } // Configure Raw Query Logging logRawQuery := EnvLogGraphQLRawQuery.IsSet() @@ -384,6 +374,7 @@ func getKeyPair() (*ecdh.PublicKey, *ecdh.PrivateKey) { } if err != nil { log.Printf("[ERROR] Unable to setup secrets manager\n") + log.Printf("[ERROR] If you're running locally try setting `export SECRETS_FILE_PATH='/tmp/secrets'` \n") } // Check if we already have a key From 1c482799b214b4f6410e793e7767c203612b30dd Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 5 May 2025 01:49:35 +0000 Subject: [PATCH 131/141] Set var so IDE is happy. --- .devcontainer/devcontainer.env | 1 + 1 file changed, 1 insertion(+) create mode 100644 .devcontainer/devcontainer.env diff --git a/.devcontainer/devcontainer.env b/.devcontainer/devcontainer.env new file mode 100644 index 000000000..474710071 --- /dev/null +++ b/.devcontainer/devcontainer.env @@ -0,0 +1 @@ +IMIX_SERVER_PUBKEY=PLACE_HOLDER From 9fb0fc48190c7d2b78e4315a04a8e26b6e4dd2ba Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Wed, 21 May 2025 01:47:44 +0000 Subject: [PATCH 132/141] Upgrades people upgrades --- go.mod | 29 ++++----- go.sum | 72 ++++++++++++---------- tavern/app.go | 2 +- tavern/internal/cryptocodec/cryptocodec.go | 46 +++++++++++--- 4 files changed, 90 insertions(+), 59 deletions(-) diff --git a/go.mod b/go.mod index 91f809d6f..33f1d08a8 100644 --- a/go.mod +++ b/go.mod @@ -18,13 +18,13 @@ require ( github.com/stretchr/testify v1.10.0 github.com/urfave/cli v1.22.5 github.com/vektah/gqlparser/v2 v2.5.21 - golang.org/x/crypto v0.31.0 - golang.org/x/net v0.33.0 - golang.org/x/oauth2 v0.24.0 - golang.org/x/sync v0.10.0 + golang.org/x/crypto v0.38.0 + golang.org/x/net v0.40.0 + golang.org/x/oauth2 v0.26.0 + golang.org/x/sync v0.14.0 google.golang.org/api v0.210.0 - google.golang.org/grpc v1.67.1 - google.golang.org/protobuf v1.36.1 + google.golang.org/grpc v1.72.1 + google.golang.org/protobuf v1.36.6 gopkg.in/yaml.v3 v3.0.1 ) @@ -60,21 +60,22 @@ require ( github.com/skeema/knownhosts v1.3.0 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect - go.opentelemetry.io/otel v1.29.0 // indirect - go.opentelemetry.io/otel/metric v1.29.0 // indirect - go.opentelemetry.io/otel/trace v1.29.0 // indirect + go.opentelemetry.io/otel v1.34.0 // indirect + go.opentelemetry.io/otel/metric v1.34.0 // indirect + go.opentelemetry.io/otel/trace v1.34.0 // indirect golang.org/x/time v0.8.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20241113202542-65e8d215514f // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect gopkg.in/warnings.v0 v0.1.2 // indirect ) require ( ariga.io/atlas v0.25.1-0.20240717145915-af51d3945208 // indirect - cloud.google.com/go/compute/metadata v0.5.2 // indirect + cloud.google.com/go/compute/metadata v0.6.0 // indirect github.com/agext/levenshtein v1.2.3 // indirect github.com/agnivade/levenshtein v1.2.0 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect @@ -102,8 +103,8 @@ require ( gocloud.dev v0.37.0 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 golang.org/x/mod v0.20.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/text v0.21.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.25.0 // indirect golang.org/x/tools v0.24.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 // indirect ) diff --git a/go.sum b/go.sum index 651701329..db564a4b4 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,8 @@ cloud.google.com/go/auth v0.11.0 h1:Ic5SZz2lsvbYcWT5dfjNWgw6tTlGi2Wc8hyQSC9BstA= cloud.google.com/go/auth v0.11.0/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI= cloud.google.com/go/auth/oauth2adapt v0.2.6 h1:V6a6XDu2lTwPZWOawrAa9HUK+DB2zfJyTuciBG5hFkU= cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8= -cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo= -cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= +cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= +cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= cloud.google.com/go/iam v1.2.2 h1:ozUSofHUGf/F4tCNy/mu9tHLTaxZFLOUiKzjcgWHGIA= cloud.google.com/go/iam v1.2.2/go.mod h1:0Ys8ccaZHdI1dEUilwzqng/6ps2YB6vRsjIe00/+6JY= cloud.google.com/go/kms v1.20.1 h1:og29Wv59uf2FVaZlesaiDAqHFzHaoUyHI3HYp9VUHVg= @@ -232,8 +232,8 @@ github.com/prometheus/common v0.61.0 h1:3gv/GThfX0cV2lpO7gkTUwZru38mxevy90Bj8YFS github.com/prometheus/common v0.61.0/go.mod h1:zr29OCN/2BsJRaFwG8QOBr41D6kkchKbpeNH7pAjb/s= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -276,18 +276,22 @@ go.einride.tech/aip v0.68.0 h1:4seM66oLzTpz50u4K1zlJyOXQ3tCzcJN7I22tKkjipw= go.einride.tech/aip v0.68.0/go.mod h1:7y9FF8VtPWqpxuAxl0KQWqaULxW4zFIesD6zF5RIHHg= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= -go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= -go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= -go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= -go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= -go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo= -go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= -go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= -go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= +go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= +go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= +go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= +go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= +go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= +go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= +go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= +go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= gocloud.dev v0.37.0 h1:XF1rN6R0qZI/9DYjN16Uy0durAmSlf58DHOcb28GPro= gocloud.dev v0.37.0/go.mod h1:7/O4kqdInCNsc6LqgmuFnS0GRew4XNNYWpA44yQnwco= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -296,8 +300,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= +golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= @@ -324,11 +328,11 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= -golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE= +golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -336,8 +340,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= +golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -354,16 +358,16 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= +golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -372,8 +376,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -401,17 +405,17 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 h1:ToEetK57OidYuqD4Q5w+vfEnPvPpuTwedCNVohYJfNk= google.golang.org/genproto v0.0.0-20241118233622-e639e219e697/go.mod h1:JJrvXBWRZaFMxBufik1a4RpFw4HhgVtBBWQeQgUj2cc= -google.golang.org/genproto/googleapis/api v0.0.0-20241113202542-65e8d215514f h1:M65LEviCfuZTfrfzwwEoxVtgvfkFkBUbFnRbxCXuXhU= -google.golang.org/genproto/googleapis/api v0.0.0-20241113202542-65e8d215514f/go.mod h1:Yo94eF2nj7igQt+TiJ49KxjIH8ndLYPZMIRSiRcEbg0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 h1:LWZqQOEjDyONlF1H6afSWpAL/znlREo2tHfLoe+8LMA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a h1:nwKuGPlUAt+aR+pcrkfFRrTU1BVrSmYyYMxYbUIVHr0= +google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a/go.mod h1:3kWAYMk1I75K4vykHtKt2ycnOgpA6974V7bREqbsenU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 h1:cJfm9zPbe1e873mHJzmQ1nwVEeRDU/T1wXDK2kUSU34= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= -google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= +google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= +google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -421,8 +425,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= -google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/tavern/app.go b/tavern/app.go index ed35d9361..7a257fd1e 100644 --- a/tavern/app.go +++ b/tavern/app.go @@ -425,7 +425,7 @@ func newGRPCHandler(client *ent.Client, grpcShellMux *stream.Mux) http.Handler { Csvc: cryptocodec.NewCryptoSvc(priv), } grpcSrv := grpc.NewServer( - grpc.ForceServerCodec(xchacha), + grpc.ForceServerCodecV2(xchacha), grpc.UnaryInterceptor(grpcWithUnaryMetrics), grpc.StreamInterceptor(grpcWithStreamMetrics), ) diff --git a/tavern/internal/cryptocodec/cryptocodec.go b/tavern/internal/cryptocodec/cryptocodec.go index 71607c230..58a52ed51 100644 --- a/tavern/internal/cryptocodec/cryptocodec.go +++ b/tavern/internal/cryptocodec/cryptocodec.go @@ -13,6 +13,7 @@ import ( "github.com/cloudflare/circl/dh/x25519" "golang.org/x/crypto/chacha20poly1305" "google.golang.org/grpc/encoding" + "google.golang.org/grpc/mem" ) // TODO: Switch to a gomap and mutex. @@ -49,9 +50,19 @@ func (s *SyncMap) Delete(key int) { // TODO: Should we make this a random long byte array in case it gets used anywhere to avoid encrypting data with a weak key? - Sliver handles errors in this way. var FAILURE_BYTES = []byte{} +func castBytesToBufSlice(buf []byte) (mem.BufferSlice, error) { + r := bytes.NewBuffer(buf) + res, e := mem.ReadAll(r, mem.DefaultBufferPool()) + if e != nil { + log.Println("[ERROR] Failed to read failure_bytes ", e) + return res, e + } + return res, nil +} + func init() { log.Println("[INFO] Loading xchacha20-poly1305") - encoding.RegisterCodec(StreamDecryptCodec{}) + encoding.RegisterCodecV2(StreamDecryptCodec{}) } type StreamDecryptCodec struct { @@ -62,30 +73,45 @@ func NewStreamDecryptCodec() StreamDecryptCodec { return StreamDecryptCodec{} } -func (s StreamDecryptCodec) Marshal(v any) ([]byte, error) { +func (s StreamDecryptCodec) Marshal(v any) (mem.BufferSlice, error) { id, err := goid() if err != nil { log.Println("[ERROR] Unable to find GOID ", id) - return FAILURE_BYTES, err + return castBytesToBufSlice(FAILURE_BYTES) } - proto := encoding.GetCodec("proto") + proto := encoding.GetCodecV2("proto") res, err := proto.Marshal(v) - enc_res := s.Csvc.Encrypt(res) - return enc_res, err + if err != nil { + log.Println("[ERROR] Unable to marshall data") + return res, err + } + enc_res := s.Csvc.Encrypt(res.Materialize()) + byte_enc_res, err := castBytesToBufSlice(enc_res) + + return byte_enc_res, err } -func (s StreamDecryptCodec) Unmarshal(buf []byte, v any) error { +func (s StreamDecryptCodec) Unmarshal(buf mem.BufferSlice, v any) error { id, err := goid() if err != nil { log.Println("[ERROR] Unable to find GOID ", id) return err } - dec_buf, pub_key := s.Csvc.Decrypt(buf) + dec_buf, pub_key := s.Csvc.Decrypt(buf.Materialize()) session_pub_keys.Store(id, pub_key) - proto := encoding.GetCodec("proto") - return proto.Unmarshal(dec_buf, v) + proto := encoding.GetCodecV2("proto") + if proto == nil { + log.Println("[ERROR] 'proto' codec is not registered") + return errors.New("'proto' codec is not registered") + } + dec_mem_slice, err := castBytesToBufSlice(dec_buf) + if err != nil { + log.Println("[ERROR] Unable to cast decrypted bytes to mem.BufferSlice") + return err + } + return proto.Unmarshal(dec_mem_slice, v) } func (s StreamDecryptCodec) Name() string { From e56c1625ab97d16098cfd71ee49e740fe4d4bde4 Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Mon, 2 Jun 2025 23:54:09 +0000 Subject: [PATCH 133/141] Updates --- docs/_docs/user-guide/imix.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_docs/user-guide/imix.md b/docs/_docs/user-guide/imix.md index b7ee0b0c8..1cac1be06 100644 --- a/docs/_docs/user-guide/imix.md +++ b/docs/_docs/user-guide/imix.md @@ -79,7 +79,7 @@ This isn't ideal as in the UI each new beacon will appear as thought it were on **We strongly recommend building agents inside the provided devcontainer `.devcontainer`** Building in the dev container limits variables that might cause issues and is the most tested way to compile. -**Imix requires a server public key so it can encrypt messsages to and from the server check the server log for `[INFO] Public key: `** +**Imix requires a server public key so it can encrypt messsages to and from the server check the server log for `[INFO] Public key: `. This base64 encoded string should be passed to the agent using the environment variable `IMIX_SERVER_PUBKEY`** ### Linux From ea00bee529f732a962a3c0ce1c426e5bf85f9375 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 28 Aug 2025 18:59:33 -0400 Subject: [PATCH 134/141] fix: update taiki-e/install-action to v2 (#951) --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5db50b7fc..0fee96f70 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -73,7 +73,7 @@ jobs: cd ./bin/reflective_loader/ cargo +nightly-2025-01-31 build --release -Z build-std=core,compiler_builtins -Z build-std-features=compiler-builtins-mem - name: Install latest nextest & cargo-llvm-cov release - uses: taiki-e/install-action@v2.52.7 + uses: taiki-e/install-action@v2 with: tool: nextest,cargo-llvm-cov - name: 🔎 Run tests From 83ab7f81d04084994e23fbd4de43db4afaf8106f Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Sat, 30 Aug 2025 02:15:04 +0000 Subject: [PATCH 135/141] Resolve golang comments --- docs/_docs/user-guide/imix.md | 2 +- tavern/app.go | 53 +++++++++++----------- tavern/internal/cryptocodec/cryptocodec.go | 36 ++++++++------- tavern/internal/secrets/debug_file.go | 42 ++++++++--------- tavern/internal/secrets/gcp.go | 9 ++-- 5 files changed, 73 insertions(+), 69 deletions(-) diff --git a/docs/_docs/user-guide/imix.md b/docs/_docs/user-guide/imix.md index 24ae2f9bb..f1da0ef25 100644 --- a/docs/_docs/user-guide/imix.md +++ b/docs/_docs/user-guide/imix.md @@ -86,7 +86,7 @@ This isn't ideal as in the UI each new beacon will appear as thought it were on **We strongly recommend building agents inside the provided devcontainer `.devcontainer`** Building in the dev container limits variables that might cause issues and is the most tested way to compile. -**Imix requires a server public key so it can encrypt messsages to and from the server check the server log for `[INFO] Public key: `. This base64 encoded string should be passed to the agent using the environment variable `IMIX_SERVER_PUBKEY`** +**Imix requires a server public key so it can encrypt messsages to and from the server check the server log for `level=INFO msg="public key: "`. This base64 encoded string should be passed to the agent using the environment variable `IMIX_SERVER_PUBKEY`** ### Linux diff --git a/tavern/app.go b/tavern/app.go index 7a257fd1e..049b70748 100644 --- a/tavern/app.go +++ b/tavern/app.go @@ -345,24 +345,24 @@ func newGraphQLHandler(client *ent.Client, repoImporter graphql.RepoImporter) ht }) } -func generate_key_pair() (*ecdh.PublicKey, *ecdh.PrivateKey, error) { - x22519 := ecdh.X25519() - priv_key, err := x22519.GenerateKey(rand.Reader) +func generateKeyPair() (*ecdh.PublicKey, *ecdh.PrivateKey, error) { + curve := ecdh.X25519() + privateKey, err := curve.GenerateKey(rand.Reader) if err != nil { - log.Printf("[ERROR] Failed to generate private key: %v\n", err) + slog.Error(fmt.Sprintf("failed to generate private key: %v\n", err)) return nil, nil, err } - public_key, err := x22519.NewPublicKey(priv_key.PublicKey().Bytes()) + publicKey, err := curve.NewPublicKey(privateKey.PublicKey().Bytes()) if err != nil { - log.Printf("[ERROR] Failed to generate public key: %v\n", err) + slog.Error(fmt.Sprintf("failed to generate public key: %v\n", err)) return nil, nil, err } - return public_key, priv_key, nil + return publicKey, privateKey, nil } func getKeyPair() (*ecdh.PublicKey, *ecdh.PrivateKey) { - x22519 := ecdh.X25519() + curve := ecdh.X25519() var secretsManager secrets.SecretsManager var err error @@ -373,52 +373,53 @@ func getKeyPair() (*ecdh.PublicKey, *ecdh.PrivateKey) { secretsManager, err = secrets.NewDebugFileSecrets(EnvSecretsManagerPath.String()) } if err != nil { - log.Printf("[ERROR] Unable to setup secrets manager\n") - log.Printf("[ERROR] If you're running locally try setting `export SECRETS_FILE_PATH='/tmp/secrets'` \n") + slog.Error("unable to setup secrets manager") + slog.Error("if you're running locally try setting `export SECRETS_FILE_PATH='/tmp/secrets'` \n") + panic("unable to connect to secrets manager") } // Check if we already have a key - priv_key_string, err := secretsManager.GetValue("tavern_encryption_private_key") + privateKeyString, err := secretsManager.GetValue("tavern_encryption_private_key") if err != nil { // Generate a new one if it doesn't exist - pub_key, priv_key, err := generate_key_pair() + pubKey, privateKey, err := generateKeyPair() if err != nil { - log.Printf("[ERROR] Key generation failed: %v", err) + slog.Error(fmt.Sprintf("key generation failed: %v", err)) return nil, nil } - priv_key_bytes, err := x509.MarshalPKCS8PrivateKey(priv_key) + privateKeyBytes, err := x509.MarshalPKCS8PrivateKey(privateKey) if err != nil { - log.Printf("[ERROR] Unable to marshal private key: %v", err) + slog.Error(fmt.Sprintf("unable to marshal private key: %v", err)) return nil, nil } - _, err = secretsManager.SetValue("tavern_encryption_private_key", priv_key_bytes) + _, err = secretsManager.SetValue("tavern_encryption_private_key", privateKeyBytes) if err != nil { - log.Printf("[ERROR] Unable to set 'tavern_encryption_private_key' using secrets manager: %v", err) + slog.Error(fmt.Sprintf("unable to set 'tavern_encryption_private_key' using secrets manager: %v", err)) return nil, nil } - return pub_key, priv_key + return pubKey, privateKey } // Parse private key bytes - tmp, err := x509.ParsePKCS8PrivateKey(priv_key_string) + tmp, err := x509.ParsePKCS8PrivateKey(privateKeyString) if err != nil { - log.Printf("[ERROR] Unable to parse private key %v\n", err) + slog.Error(fmt.Sprintf("unable to parse private key %v", err)) } - priv_key := tmp.(*ecdh.PrivateKey) + privateKey := tmp.(*ecdh.PrivateKey) - public_key, err := x22519.NewPublicKey(priv_key.PublicKey().Bytes()) + publicKey, err := curve.NewPublicKey(privateKey.PublicKey().Bytes()) if err != nil { - log.Printf("[ERROR] Failed to generate public key: %v\n", err) - panic("[ERROR] Failed to generate public key") + slog.Error(fmt.Sprintf("failed to generate public key: %v\n", err)) + panic("failed to generate public key") } - return public_key, priv_key + return publicKey, privateKey } func newGRPCHandler(client *ent.Client, grpcShellMux *stream.Mux) http.Handler { pub, priv := getKeyPair() - log.Println("[INFO] Public key: ", base64.StdEncoding.EncodeToString(pub.Bytes())) + slog.Info(fmt.Sprintf("public key: %s", base64.StdEncoding.EncodeToString(pub.Bytes()))) c2srv := c2.New(client, grpcShellMux) xchacha := cryptocodec.StreamDecryptCodec{ diff --git a/tavern/internal/cryptocodec/cryptocodec.go b/tavern/internal/cryptocodec/cryptocodec.go index 58a52ed51..61b390e91 100644 --- a/tavern/internal/cryptocodec/cryptocodec.go +++ b/tavern/internal/cryptocodec/cryptocodec.go @@ -5,7 +5,9 @@ import ( "crypto/ecdh" "crypto/rand" "errors" + "fmt" "log" + "log/slog" "runtime" "strconv" "sync" @@ -54,7 +56,7 @@ func castBytesToBufSlice(buf []byte) (mem.BufferSlice, error) { r := bytes.NewBuffer(buf) res, e := mem.ReadAll(r, mem.DefaultBufferPool()) if e != nil { - log.Println("[ERROR] Failed to read failure_bytes ", e) + slog.Error(fmt.Sprintf("failed to read failure_bytes %s", e)) return res, e } return res, nil @@ -76,13 +78,13 @@ func NewStreamDecryptCodec() StreamDecryptCodec { func (s StreamDecryptCodec) Marshal(v any) (mem.BufferSlice, error) { id, err := goid() if err != nil { - log.Println("[ERROR] Unable to find GOID ", id) + slog.Error(fmt.Sprintf("unable to find GOID %d", id)) return castBytesToBufSlice(FAILURE_BYTES) } proto := encoding.GetCodecV2("proto") res, err := proto.Marshal(v) if err != nil { - log.Println("[ERROR] Unable to marshall data") + slog.Error("Unable to marshall data") return res, err } enc_res := s.Csvc.Encrypt(res.Materialize()) @@ -94,7 +96,7 @@ func (s StreamDecryptCodec) Marshal(v any) (mem.BufferSlice, error) { func (s StreamDecryptCodec) Unmarshal(buf mem.BufferSlice, v any) error { id, err := goid() if err != nil { - log.Println("[ERROR] Unable to find GOID ", id) + slog.Error(fmt.Sprintf("unable to find GOID %d", id)) return err } dec_buf, pub_key := s.Csvc.Decrypt(buf.Materialize()) @@ -103,12 +105,12 @@ func (s StreamDecryptCodec) Unmarshal(buf mem.BufferSlice, v any) error { proto := encoding.GetCodecV2("proto") if proto == nil { - log.Println("[ERROR] 'proto' codec is not registered") + slog.Error("'proto' codec is not registered") return errors.New("'proto' codec is not registered") } dec_mem_slice, err := castBytesToBufSlice(dec_buf) if err != nil { - log.Println("[ERROR] Unable to cast decrypted bytes to mem.BufferSlice") + slog.Error("Unable to cast decrypted bytes to mem.BufferSlice") return err } return proto.Unmarshal(dec_mem_slice, v) @@ -133,13 +135,13 @@ func (csvc *CryptoSvc) generate_shared_key(client_pub_key_bytes []byte) []byte { x22519_curve := ecdh.X25519() client_pub_key, err := x22519_curve.NewPublicKey(client_pub_key_bytes) if err != nil { - log.Printf("[ERROR] Failed to create public key %v\n", err) + slog.Error(fmt.Sprintf("failed to create public key %v", err)) return FAILURE_BYTES } shared_key, err := csvc.priv_key.ECDH(client_pub_key) if err != nil { - log.Printf("[ERROR] Failed to get shared secret %v\n", err) + slog.Error(fmt.Sprintf("failed to get shared secret %v", err)) return FAILURE_BYTES } @@ -149,7 +151,7 @@ func (csvc *CryptoSvc) generate_shared_key(client_pub_key_bytes []byte) []byte { func (csvc *CryptoSvc) Decrypt(in_arr []byte) ([]byte, []byte) { // Read in pub key if len(in_arr) < x25519.Size { - log.Printf("[ERROR] Input bytes to short %d expected at least %d\n", len(in_arr), x25519.Size) + slog.Error(fmt.Sprintf("input bytes to short %d expected at least %d", len(in_arr), x25519.Size)) return FAILURE_BYTES, FAILURE_BYTES } @@ -157,7 +159,7 @@ func (csvc *CryptoSvc) Decrypt(in_arr []byte) ([]byte, []byte) { id, err := goid() if err != nil { - log.Println("[ERROR] Failed to get goid") + slog.Error("failed to get goid") return FAILURE_BYTES, FAILURE_BYTES } session_pub_keys.Store(id, client_pub_key_bytes) @@ -167,7 +169,7 @@ func (csvc *CryptoSvc) Decrypt(in_arr []byte) ([]byte, []byte) { aead, err := chacha20poly1305.NewX(derived_key) if err != nil { - log.Printf("[ERROR] Failed to create xchacha key %v\n", err) + slog.Error(fmt.Sprintf("failed to create xchacha key %v", err)) return FAILURE_BYTES, FAILURE_BYTES } @@ -176,7 +178,7 @@ func (csvc *CryptoSvc) Decrypt(in_arr []byte) ([]byte, []byte) { // Read nonce & cipher text if len(in_arr) < aead.NonceSize() { - log.Printf("[ERROR] Input bytes to short %d expected at least %d\n", len(in_arr), aead.NonceSize()) + slog.Error(fmt.Sprintf("input bytes to short %d expected at least %d", len(in_arr), aead.NonceSize())) return FAILURE_BYTES, FAILURE_BYTES } nonce, ciphertext := in_arr[:aead.NonceSize()], in_arr[aead.NonceSize():] @@ -184,7 +186,7 @@ func (csvc *CryptoSvc) Decrypt(in_arr []byte) ([]byte, []byte) { // Decrypt plaintext, err := aead.Open(nil, nonce, ciphertext, nil) if err != nil { - log.Printf("[ERROR] Failed to decrypt %v\n", err) + slog.Error(fmt.Sprintf("failed to decrypt %v", err)) return FAILURE_BYTES, FAILURE_BYTES } @@ -196,13 +198,13 @@ func (csvc *CryptoSvc) Encrypt(in_arr []byte) []byte { // Get the client pub key? id, err := goid() if err != nil { - log.Println("[ERROR] Unable to find GOID ", id) + slog.Error(fmt.Sprintf("unable to find GOID %d", id)) return FAILURE_BYTES } client_pub_key_bytes, ok := session_pub_keys.Load(id) if !ok { - log.Println("[ERROR] Public key not found") + slog.Error("Public key not found") return FAILURE_BYTES } @@ -213,13 +215,13 @@ func (csvc *CryptoSvc) Encrypt(in_arr []byte) []byte { shared_key := csvc.generate_shared_key(client_pub_key_bytes) aead, err := chacha20poly1305.NewX(shared_key) if err != nil { - log.Printf("[ERROR] Failed to create xchacha key %v\n", err) + slog.Error(fmt.Sprintf("failed to create xchacha key %v", err)) return FAILURE_BYTES } nonce := make([]byte, aead.NonceSize(), aead.NonceSize()+len(in_arr)+aead.Overhead()) if _, err := rand.Read(nonce); err != nil { - log.Printf("[ERROR] Failed to encrypt %v\n", err) + slog.Error(fmt.Sprintf("Failed to encrypt %v", err)) return FAILURE_BYTES } encryptedMsg := aead.Seal(nonce, nonce, in_arr, nil) diff --git a/tavern/internal/secrets/debug_file.go b/tavern/internal/secrets/debug_file.go index 076c84040..77b6df8d9 100644 --- a/tavern/internal/secrets/debug_file.go +++ b/tavern/internal/secrets/debug_file.go @@ -3,7 +3,7 @@ package secrets import ( "errors" "fmt" - "log" + "log/slog" "os" "gopkg.in/yaml.v3" @@ -19,9 +19,9 @@ type Secret struct { Value string } -type Secrets struct { - Secrets []Secret -} + +type Secrets []Secret + type DebugFileSecrets struct { Name string @@ -42,30 +42,30 @@ func (s DebugFileSecrets) GetName() string { func (s DebugFileSecrets) SetValue(key string, value []byte) ([]byte, error) { path, err := s.ensureSecretsFileExist() if err != nil { - log.Printf("[ERROR] Failed to create secrets file %s: %v", path, err) + slog.Error("failed to create secrets file %s: %v", path, err) return []byte{}, err } secrets, err := s.getYamlStruct(path) if err != nil { - log.Printf("[ERROR] Failed to parse YAML file %s: %v", path, err) + slog.Error("failed to parse YAML file %s: %v", path, err) return []byte{}, err } var old_value []byte = []byte{} // If the value exists update it - for idx, k := range secrets.Secrets { + for idx, k := range secrets { if k.Key == key { - secrets.Secrets[idx].Value = string(value) + secrets[idx].Value = string(value) old_value = []byte(k.Value) } } // If the value doesn't exist create it if len(old_value) == 0 { - secrets.Secrets = append( - secrets.Secrets, + secrets = append( + secrets, Secret{ Key: key, Value: string(value), @@ -75,7 +75,7 @@ func (s DebugFileSecrets) SetValue(key string, value []byte) ([]byte, error) { err = s.setYamlStruct(path, secrets) if err != nil { - log.Printf("[ERROR] Failed to update YAML file %s: %v", path, err) + slog.Error("failed to update YAML file %s: %v", path, err) return []byte{}, err } @@ -87,11 +87,11 @@ func (s DebugFileSecrets) GetValue(key string) ([]byte, error) { secrets, err := s.getYamlStruct(path) if err != nil { - log.Printf("[ERROR] Failed to parse YAML file %s: %v", path, err) + slog.Error("failed to parse YAML file %s: %v", path, err) return []byte{}, err } - for _, k := range secrets.Secrets { + for _, k := range secrets { if k.Key == key { return []byte(k.Value), nil } @@ -103,20 +103,20 @@ func (s DebugFileSecrets) GetValue(key string) ([]byte, error) { func (s DebugFileSecrets) setYamlStruct(path string, secrets Secrets) error { data, err := yaml.Marshal(secrets) if err != nil { - fmt.Printf("[ERROR] Failed to parse file YAML %s: %v", path, err) + slog.Error("failed to parse file YAML %s: %v", path, err) return err } file, err := os.OpenFile(path, os.O_RDWR, DEFAULT_PERMS) if err != nil { - log.Printf("[ERROR] Failed to open secrets file %s: %v", path, err) + slog.Error("failed to open secrets file %s: %v", path, err) return err } defer file.Close() _, err = file.Write(data) if err != nil { - log.Printf("[ERROR] Failed to read file %s: %v", path, err) + slog.Error("failed to read file %s: %v", path, err) return err } @@ -126,7 +126,7 @@ func (s DebugFileSecrets) setYamlStruct(path string, secrets Secrets) error { func (s DebugFileSecrets) getYamlStruct(path string) (Secrets, error) { file, err := os.OpenFile(path, os.O_RDWR, DEFAULT_PERMS) if err != nil { - log.Printf("[ERROR] Failed to open secrets file %s: %v", path, err) + slog.Error("failed to open secrets file %s: %v", path, err) return Secrets{}, err } defer file.Close() @@ -134,7 +134,7 @@ func (s DebugFileSecrets) getYamlStruct(path string) (Secrets, error) { data := make([]byte, MAX_FILE_SIZE) n, err := file.Read(data) if err != nil { - log.Printf("[ERROR] Failed to read file %s: %v", path, err) + slog.Error("failed to read file %s: %v", path, err) return Secrets{}, err } @@ -143,7 +143,7 @@ func (s DebugFileSecrets) getYamlStruct(path string) (Secrets, error) { var secrets Secrets err = yaml.Unmarshal(data, &secrets) if err != nil { - fmt.Printf("[ERROR] Failed to parse file YAML %s: %v", path, err) + slog.Error("failed to parse file YAML %s: %v", path, err) return Secrets{}, err } @@ -156,7 +156,7 @@ func (s DebugFileSecrets) ensureSecretsFileExist() (string, error) { // Create file f, err := os.OpenFile(s.Path, os.O_CREATE, DEFAULT_PERMS) if err != nil { - log.Printf("[ERROR] Failed to create file %s\n", s.Path) + slog.Error(fmt.Sprintf("failed to create file %s", s.Path)) return s.Path, err } defer f.Close() @@ -164,7 +164,7 @@ func (s DebugFileSecrets) ensureSecretsFileExist() (string, error) { // Write empty struct to file err = s.setYamlStruct(s.Path, Secrets{}) if err != nil { - log.Printf("[ERROR] Failed to set yaml struct") + slog.Error("failed to set yaml struct") return s.Path, err } } diff --git a/tavern/internal/secrets/gcp.go b/tavern/internal/secrets/gcp.go index 54c05d7a6..89c10a49d 100644 --- a/tavern/internal/secrets/gcp.go +++ b/tavern/internal/secrets/gcp.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "log" + "log/slog" "strings" secretmanager "cloud.google.com/go/secretmanager/apiv1" @@ -39,7 +40,7 @@ func (g Gcp) GetValue(key string) ([]byte, error) { // Call the API. result, err := g.client.AccessSecretVersion(g.clientctx, accessRequest) if err != nil { - log.Printf("[ERROR] failed to access secret version: %v\n", err) + slog.Error(fmt.Sprintf("failed to access secret version: %v", err)) return []byte{}, err } @@ -82,7 +83,7 @@ func (g Gcp) SetValue(key string, value []byte) ([]byte, error) { old_value, err := g.GetValue(key) if err != nil && !strings.Contains(err.Error(), "code = NotFound") { - log.Printf("[ERROR] Failed to get old secret: %v\n", err) + slog.Error(fmt.Sprintf("failed to get old secret: %v", err)) return []byte{}, err } @@ -116,7 +117,7 @@ func NewGcp(projectID string) (SecretsManager, error) { tmp, err := GetCurrentGcpProject(ctx) projectID = tmp if err != nil { - log.Printf("[ERROR] Failed to get current project ID: %v\n", err) + slog.Error(fmt.Sprintf("failed to get current project ID: %v\n", err)) return nil, err } } @@ -125,7 +126,7 @@ func NewGcp(projectID string) (SecretsManager, error) { // Create the client. client, err := secretmanager.NewClient(ctx) if err != nil { - log.Printf("[ERROR] Failed to setup client: %v\n", err) + slog.Error(fmt.Sprintf("failed to setup client: %v\n", err)) return nil, err } From ba9e4793317551ad187d87e456521311f8db0ab5 Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Sat, 30 Aug 2025 03:15:39 +0000 Subject: [PATCH 136/141] First pass --- implants/lib/pb/src/xchacha.rs | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index 3c0d48e7f..b939b61ab 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -24,6 +24,9 @@ static SERVER_PUBKEY: [u8; 32] = const_decode::Base64.decode(env!("IMIX_SERVER_P // ------------ +// The client and server may have multiple connections open and they may not resolve in order or sequentially. +// To handle this ephemeral public keys and shared secrets are stored in a hashmap key_history where they can be looked up +// by public key. fn key_history() -> &'static Mutex> { static ARRAY: OnceLock>> = OnceLock::new(); ARRAY.get_or_init(|| Mutex::new(HashMap::new())) @@ -34,11 +37,12 @@ fn add_key_history(pub_key: [u8; 32], shared_secret: [u8; 32]) { } fn get_key(pub_key: [u8; 32]) -> Result<[u8; 32]> { + // Lookup the shared secret based on the public key let res = *key_history() .lock() .unwrap() // Mutex's must unwrap .get(&pub_key) - .context("Key not found")?; + .context("Unable to find shared secret for the public key recieved")?; Ok(res) } @@ -96,7 +100,7 @@ where fn encode(&mut self, item: Self::Item, buf: &mut EncodeBuf<'_>) -> Result<(), Self::Error> { if !buf.has_remaining_mut() { - // Can't add to the buffer. + // This should never happen but if it does the agent will be unable to queue new messages to the buffer until it's drained. #[cfg(debug_assertions)] log::debug!("DANGER can't add to the buffer."); } @@ -125,7 +129,7 @@ where Ok(ct) => ct, Err(err) => { #[cfg(debug_assertions)] - log::debug!("err: {:?}", err); + log::debug!("encode error unable to read bytes while encrypting: {:?}", err); return Err(Status::new(tonic::Code::Internal, err.to_string())); } }; @@ -164,12 +168,16 @@ where Ok(n) => n, Err(err) => { #[cfg(debug_assertions)] - log::debug!("err: {:?}", err); + log::debug!("decode error unable to read bytes from decode reader: {:?}", err); return Err(Status::new(tonic::Code::Internal, err.to_string())); } }; - // TODO validate buffer size to avoid index out of bounds accesses + if bytes_read < PUBKEY_LEN + NONCE_LEN { + let err = anyhow::anyhow!("Message from server is too small to contain public key and nonce"); + log::debug!("Input buffer from server during decode faild validation: {:?}", err); + return Err(Status::new(tonic::Code::Internal, err.to_string())); + } let buf = bytes_in .get(0..bytes_read) .context("Bytes read doesn't match buffer size") @@ -192,7 +200,18 @@ where // Get private key based on messages public key let tmp_client_public_bytes = client_public.to_vec(); - let client_public_bytes = tmp_client_public_bytes.try_into().unwrap(); // Bruh idk how to not unwrap this :sob: + let client_public_bytes = match tmp_client_public_bytes.try_into() { + Ok(arr) => arr, + Err(err) => { + #[cfg(debug_assertions)] + log::debug!("Unable to cast public key bytes from vector to slice during decode function: {:?}", err); + + return Err(Status::new( + tonic::Code::Internal, + "Unable to cast public key bytes from vector to slice during decode function", + )); + } + }; let client_private_bytes = get_key(client_public_bytes).map_err(from_anyhow_error)?; // Shouldn't need private key again once the message has been decrypted From 3b9b315377b80c1dd91a15c9920a002587c44806 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Sat, 30 Aug 2025 01:01:54 -0400 Subject: [PATCH 137/141] fix(tests): update secrets test to match new struct (#955) --- tavern/internal/secrets/debug_file_test.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tavern/internal/secrets/debug_file_test.go b/tavern/internal/secrets/debug_file_test.go index 92a6ff674..add301533 100644 --- a/tavern/internal/secrets/debug_file_test.go +++ b/tavern/internal/secrets/debug_file_test.go @@ -15,11 +15,10 @@ func createTestSecrets(t *testing.T) string { tmpDir := t.TempDir() secretsPath := path.Join(tmpDir, "secrets.yaml") data := []byte(` -secrets: - - key: TAVERN_PRIVATE_KEY - value: !!binary Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE= - - key: super_secret_test_data - value: hello world! +- key: TAVERN_PRIVATE_KEY + value: !!binary Fe8E/SVf7MLgCHzBWvjdnavejsJijJZD9mPvLQbgybE= +- key: super_secret_test_data + value: hello world! `) err := os.WriteFile(secretsPath, data, 0644) if err != nil { From 887bb0ebdf48c6488c63c178f7c4de88901f1473 Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Sat, 30 Aug 2025 14:20:16 +0000 Subject: [PATCH 138/141] Fix lint error --- .vscode/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 376f8d907..72430bbe1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,7 +4,7 @@ "rust-analyzer" ], "rust-analyzer.server.extraEnv": { - "IMIX_SERVER_PUBKEY": "[OVERRIDE THIS VARIABLE]" + "IMIX_SERVER_PUBKEY": "v3NEg3eB9/e3wi4HHSoIIgPq3BEi6xrurKOSuOVj72g=" }, "rust-analyzer.check.command": "clippy", "rust-analyzer.showUnlinkedFileNotification": false, From 561b1fdf889a55ab6cdab2f797387eedb0bb7549 Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Sat, 30 Aug 2025 14:25:01 +0000 Subject: [PATCH 139/141] format --- implants/lib/pb/src/xchacha.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index b939b61ab..00420b69e 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -129,7 +129,10 @@ where Ok(ct) => ct, Err(err) => { #[cfg(debug_assertions)] - log::debug!("encode error unable to read bytes while encrypting: {:?}", err); + log::debug!( + "encode error unable to read bytes while encrypting: {:?}", + err + ); return Err(Status::new(tonic::Code::Internal, err.to_string())); } }; @@ -168,14 +171,21 @@ where Ok(n) => n, Err(err) => { #[cfg(debug_assertions)] - log::debug!("decode error unable to read bytes from decode reader: {:?}", err); + log::debug!( + "decode error unable to read bytes from decode reader: {:?}", + err + ); return Err(Status::new(tonic::Code::Internal, err.to_string())); } }; if bytes_read < PUBKEY_LEN + NONCE_LEN { - let err = anyhow::anyhow!("Message from server is too small to contain public key and nonce"); - log::debug!("Input buffer from server during decode faild validation: {:?}", err); + let err = + anyhow::anyhow!("Message from server is too small to contain public key and nonce"); + log::debug!( + "Input buffer from server during decode faild validation: {:?}", + err + ); return Err(Status::new(tonic::Code::Internal, err.to_string())); } let buf = bytes_in From 55129400f68942ae2b120894107a7274f99e42c9 Mon Sep 17 00:00:00 2001 From: Hulto <7121375+hulto@users.noreply.github.com> Date: Sat, 30 Aug 2025 10:40:17 -0400 Subject: [PATCH 140/141] test: Add test for key_history size limit (#954) Adds a new test to ensure that the `key_history` LRU cache does not grow beyond its specified size limit of 1024 entries. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- implants/Cargo.toml | 1 + implants/lib/pb/Cargo.toml | 1 + implants/lib/pb/src/xchacha.rs | 41 ++++++++++++++++++++++++++++------ 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/implants/Cargo.toml b/implants/Cargo.toml index 4c9fc2e0b..01a42f2a9 100644 --- a/implants/Cargo.toml +++ b/implants/Cargo.toml @@ -92,6 +92,7 @@ winreg = "0.51.0" chacha20poly1305 = "0.10.1" bytes = "1.6.0" x25519-dalek = "2.0.1" +lru = "0.16.0" [profile.release] diff --git a/implants/lib/pb/Cargo.toml b/implants/lib/pb/Cargo.toml index ea1c38781..79764df2e 100644 --- a/implants/lib/pb/Cargo.toml +++ b/implants/lib/pb/Cargo.toml @@ -19,6 +19,7 @@ chacha20poly1305 = { workspace = true } bytes = { workspace = true } rand = { workspace = true } x25519-dalek = { workspace = true } +lru = { workspace = true } uuid = { workspace = true, features = ["v4", "fast-rng"] } whoami = { workspace = true } diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index 00420b69e..380b41318 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -5,10 +5,11 @@ use const_decoder::Decoder as const_decode; use prost::Message; use rand::rngs::OsRng; use rand_chacha::rand_core::SeedableRng; +use lru::LruCache; use std::{ - collections::HashMap, io::{Read, Write}, marker::PhantomData, + num::NonZeroUsize, sync::{Mutex, OnceLock}, }; use tonic::{ @@ -24,16 +25,22 @@ static SERVER_PUBKEY: [u8; 32] = const_decode::Base64.decode(env!("IMIX_SERVER_P // ------------ +const KEY_CACHE_SIZE: usize = 1024; + // The client and server may have multiple connections open and they may not resolve in order or sequentially. // To handle this ephemeral public keys and shared secrets are stored in a hashmap key_history where they can be looked up // by public key. -fn key_history() -> &'static Mutex> { - static ARRAY: OnceLock>> = OnceLock::new(); - ARRAY.get_or_init(|| Mutex::new(HashMap::new())) +fn key_history() -> &'static Mutex> { + static ARRAY: OnceLock>> = OnceLock::new(); + ARRAY.get_or_init(|| { + Mutex::new(LruCache::new( + NonZeroUsize::new(KEY_CACHE_SIZE).unwrap(), + )) + }) } fn add_key_history(pub_key: [u8; 32], shared_secret: [u8; 32]) { - key_history().lock().unwrap().insert(pub_key, shared_secret); // Mutex's must unwrap + key_history().lock().unwrap().put(pub_key, shared_secret); // Mutex's must unwrap } fn get_key(pub_key: [u8; 32]) -> Result<[u8; 32]> { @@ -46,8 +53,8 @@ fn get_key(pub_key: [u8; 32]) -> Result<[u8; 32]> { Ok(res) } -fn del_key(pub_key: [u8; 32]) -> Option<([u8; 32], [u8; 32])> { - key_history().lock().unwrap().remove_entry(&pub_key) +fn del_key(pub_key: [u8; 32]) -> Option<[u8; 32]> { + key_history().lock().unwrap().pop(&pub_key) } // ------------ @@ -259,3 +266,23 @@ fn from_decode_error(error: prost::DecodeError) -> Status { // https://github.com/grpc/grpc/blob/master/doc/statuscodes.md Status::new(tonic::Code::Internal, error.to_string()) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_key_history_bounded() { + let mut key_history = key_history().lock().unwrap(); + for i in 0..KEY_CACHE_SIZE * 2 { + let mut pub_key = [0u8; 32]; + let mut shared_secret = [0u8; 32]; + pub_key[0] = i as u8; + pub_key[1] = (i >> 8) as u8; + shared_secret[0] = i as u8; + shared_secret[1] = (i >> 8) as u8; + key_history.put(pub_key, shared_secret); + } + assert_eq!(key_history.len(), KEY_CACHE_SIZE); + } +} From 69695ec9ec56b8cb0ac28768617dba4adba5da5d Mon Sep 17 00:00:00 2001 From: hulto <7121375+hulto@users.noreply.github.com> Date: Sat, 30 Aug 2025 14:46:18 +0000 Subject: [PATCH 141/141] format --- implants/lib/pb/src/xchacha.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/implants/lib/pb/src/xchacha.rs b/implants/lib/pb/src/xchacha.rs index 380b41318..a87ede72f 100644 --- a/implants/lib/pb/src/xchacha.rs +++ b/implants/lib/pb/src/xchacha.rs @@ -2,10 +2,10 @@ use anyhow::{Context, Result}; use bytes::{Buf, BufMut}; use chacha20poly1305::{aead::generic_array::GenericArray, aead::Aead, AeadCore, KeyInit}; use const_decoder::Decoder as const_decode; +use lru::LruCache; use prost::Message; use rand::rngs::OsRng; use rand_chacha::rand_core::SeedableRng; -use lru::LruCache; use std::{ io::{Read, Write}, marker::PhantomData, @@ -32,11 +32,7 @@ const KEY_CACHE_SIZE: usize = 1024; // by public key. fn key_history() -> &'static Mutex> { static ARRAY: OnceLock>> = OnceLock::new(); - ARRAY.get_or_init(|| { - Mutex::new(LruCache::new( - NonZeroUsize::new(KEY_CACHE_SIZE).unwrap(), - )) - }) + ARRAY.get_or_init(|| Mutex::new(LruCache::new(NonZeroUsize::new(KEY_CACHE_SIZE).unwrap()))) } fn add_key_history(pub_key: [u8; 32], shared_secret: [u8; 32]) {