-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NATS backend support #59
Conversation
Add NATS JetStream Object Store backend support
updated go.mod and go.sum for NATS
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned in #59, any new storage backends must live in separate repositories. We would love to see one and link to it in the README.
This is a courtesy review with no intention to merge.
// Simple encryption helper | ||
func helperEncrypt(key []byte, plaintext []byte) ([]byte, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I cannot say I am charmed by undocumented DIY crypto implementations.
Also please read the points in #52 (comment)
Perhaps any client side encryption should be implemented as an swappable middleware layer between simpleblob and the application that can be used by multiple backends?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the subject of "undocumented DIY crypto implementations."
Far from the case. I would point out that it is (a) nothing but a thin-wrapper around Go stdlib crypto (b) the implementation is basically nothing more than a copy/paste of the example from the Go docs (https://pkg.go.dev/golang.org/x/crypto/chacha20poly1305#example-NewX). The only significant difference is I don't panic()
but return the error. 😉
Sadly NATS does not have built-in object-level SSE-C otherwise I would have gladly used that.
Thanks for all the feedback though, much appreciated food for thought.
// Options enumerates various configuration options | ||
type Options struct { | ||
// Params related to reconnection attempts | ||
DisableRetryOnFailedConnect bool `yaml:"disableRetryOnFailedConnect"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All the other simpleblob backends use disable_retry_on_failed_connect
style options, which are more common for yaml, at least in Go.
// Params related to reconnection attempts | ||
DisableRetryOnFailedConnect bool `yaml:"disableRetryOnFailedConnect"` | ||
MaxReconnects int `yaml:"maxReconnects"` | ||
ReconnectWaitSeconds int `yaml:"reconnectWait"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Options that are a duration should directly use time.Duration
.
// DefaultMaxReconnects - Max Reconnect attempts | ||
DefaultMaxReconnects = 5 | ||
// DefaultReconnectWaitSeconds - Time to wait before attempting reconnect | ||
DefaultReconnectWaitSeconds = 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use time.Duration
instead, like
DefaultReconnectWaitSeconds = 1 | |
DefaultReconnectWait = 1 * time.Second |
username authType = iota | ||
token | ||
nkey | ||
credentials | ||
nkeyJwt | ||
jwt | ||
invalid |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Global enums should have a common prefix for readability, otherwise it is hard to understand where that token
is suddenly coming from, e.g. AuthUsername
, AuthToken
, etc.
// Auth type flag set internally by checkCredentialsAvailability() | ||
internalUseAuthType authType | ||
// Converted type for wait seconds | ||
internalReconnectWaitSeconds time.Duration |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't add Seconds to the name if it's a Duration.
As mentioned elsewhere, there is no need to convert. You can just directly use time.Duration.
// EncryptionKey - key (hex format,256 bit) for encryption at rest | ||
EncryptionKey string `yaml:"encryptionKey"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See other comment about homegrown encryption.
GlobalPrefix string `yaml:"global_prefix"` | ||
// EncryptionKey - key (hex format,256 bit) for encryption at rest | ||
EncryptionKey string `yaml:"encryptionKey"` | ||
// S3 Compatability |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not S3.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per comment below, the problem was the need for tester/DoBackendTests
conformance.
if o.NatsTLSRootCA != "" { | ||
err := fileExistsAndIsReadable(o.NatsTLSRootCA) | ||
if err != nil { | ||
return err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may want to wrap this in a hint about which option is incorrect. Same elsewhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just FYI, my intention with this and most of the NATS options was "you know if you need them", i.e. you know if your environment is using an in-house CA (and therefore you need to provide the root pubkey), you know what auth-type your environment is using (and therefore you know if you need to provide an NKey or a username/password) etc.
Hence I did not expend much effort explaining in detail what every option was.
// prependGlobalPrefix prepends the GlobalPrefix to the name/prefix | ||
// passed as input | ||
func (b *Backend) prependGlobalPrefix(name string) string { | ||
return b.opt.GlobalPrefix + name | ||
} | ||
|
||
// setGlobalPrefix updates the global prefix in b and the cached marker name, | ||
// so it can be dynamically changed in tests. | ||
func (b *Backend) setGlobalPrefix(prefix string) { | ||
b.opt.GlobalPrefix = prefix | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefixes made sense in the context of S3 buckets, but perhaps not in the context of NATS buckets that can easily be created on the fly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ultimatley the fundamental problem if I was testing the backend against tester/DoBackendTests
then I had little choice to implement prefix support, otherwise DoBackendTests
would complain.
Code to add NATS SSE-C Support #55
Was originally PR #56 , but I made a mess of that fork. So this is based off a clean fork with the code in its own branch to keep it clean.
N.B. go.mod will need to be bumped to min. 1.20 due to NATS dependency (that is also why the CI is failing because CI is currently running against old go.mod)