Skip to content
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

CSS-4936 Postgres as secret backend #1011

Merged

Conversation

kian99
Copy link
Contributor

@kian99 kian99 commented Jul 26, 2023

Description

Added Postgres as a secret backend so that it satisfies the CredentialStore interface. JIMM will only use Postgres as a secret backend if Vault is not available and an explicit env var is set.

Also refactored slightly our migration code as that didn't work when a new migration was added.

Engineering checklist

Check only items that apply

  • Documentation updated
  • Covered by unit tests
  • Covered by integration tests

Test instructions

Tested by spinning up the Docker compose and curling the well-known endpoint and verifying the data in Postgres.

@kian99 kian99 changed the title CSS - 4936 Postgres as secret backend CSS-4936 Postgres as secret backend Jul 26, 2023
@@ -189,6 +196,34 @@ def test_bakery_configuration(self):
},
)

def test_audit_log_retention_config(self):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added this test as I noticed nothing was testing it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahhh ty

"audit-log-retention-period-in-days": "10",
}

EXPECTED_ENV = {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drive-by fix for less duplication in the k8s charm tests.

@@ -70,7 +70,7 @@ func (d *Database) Migrate(ctx context.Context, force bool) error {
}

for {
v := dbmodel.Version{Component: dbmodel.Component}
v := dbmodel.Version{Component: dbmodel.Component, Major: 1, Minor: 0}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So to quickly discuss the changes to the migrations, when I added a migration it didn't take effect because the code didn't quite work right. Essentially the problem boiled down to the fact that our first migration was 0_0 and the default value for the struct/DB was also 0 so we had no way of knowing if a migration had taken place after the initial one was done. So the simplest solution is to start our migrations from 1. That is why you will notice our migrations now start at 1_1. This change is best left to feature-rebac since we haven't deployed it (for our staging deploy I can manually tweak things in the DB) and the schema is different to main anyway.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good to me, but I'm not sure how we were able to migrate up to this point? Perhaps discuss this in standup later / explain it as I don't think I fully understand.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first migration worked, but the second wouldn't. At the end of the first migration there was a line UPDATE versions SET major=1, minor=0 WHERE component='jimmdb'; now after that migration takes place, the code will query the versions table and see that MajorDesired==MajorSet and MinorRequired>MinorSet so it would try to run the next migration but it doesn't know what the next migration is, and that's why I had to add the Minor+=1 line. And the last thing is that when I added that line but the first migration starts at 0, we have a problem.

internal/db/secrets.go Outdated Show resolved Hide resolved
internal/db/secrets.go Outdated Show resolved Hide resolved
internal/db/secrets.go Outdated Show resolved Hide resolved
// newSecret creates a secret object with the time set to the current time
// and the type and tag fields set from the tag object
func newSecret(secretType string, secretTag string, data []byte) dbmodel.Secret {
return dbmodel.Secret{Time: time.Now(), Type: secretType, Tag: secretTag, Data: data}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably needs validation, I notice we check if tag and type exist and duplicate it a lot, couldn't this just return an error and we do it in the constructor for the secret?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What kind of validation? And not sure what you mean by

we check if tag and type exist and duplicate it a lot

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

	if secret.Tag == "" || secret.Type == "" {
		return errors.E(op, "missing secret tag and type", errors.CodeBadRequest)
	}

Thing like this ^

internal/db/secrets.go Outdated Show resolved Hide resolved
@@ -299,6 +299,11 @@ func NewService(ctx context.Context, p Params) (*Service, error) {
}
if vs != nil {
s.jimm.CredentialStore = vs
} else {
// Only enable Postgres storage for secrets if explictly enabled.
if _, ok := os.LookupEnv("INSECURE_SECRET_STORAGE"); ok {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if this isn't ok, the service will just fail to put secrets right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, which is the existing behaviour.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's discuss this later too, we should exit here I feel

Copy link
Contributor

@ale8k ale8k left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a fair few comments sorry, will update once resolved

Copy link
Member

@babakks babakks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice job. Just had a few comments.

cmd/jimmsrv/main.go Show resolved Hide resolved
docker-compose.yaml Show resolved Hide resolved
internal/db/secrets.go Show resolved Hide resolved
internal/db/secrets.go Outdated Show resolved Hide resolved
internal/db/secrets.go Outdated Show resolved Hide resolved
internal/db/secrets.go Show resolved Hide resolved
internal/db/secrets.go Show resolved Hide resolved
internal/db/secrets_test.go Show resolved Hide resolved
internal/db/secrets_test.go Show resolved Hide resolved
service.go Show resolved Hide resolved
internal/db/secrets.go Show resolved Hide resolved
- Added logging
- Fixed broken test
- Fixed cleanup JWKS function
Copy link
Contributor

@ale8k ale8k left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm now

@kian99 kian99 merged commit e348f24 into canonical:feature-rebac Jul 26, 2023
7 checks passed
@kian99 kian99 deleted the CSS-4936-postgres-as-secret-backend branch July 26, 2023 14:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants