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

A secret vault storage with AES encryption using a certificate #56

Merged
merged 26 commits into from
Jul 30, 2018

Conversation

Skarlso
Copy link
Member

@Skarlso Skarlso commented Jul 24, 2018

Deals with #51.

TODO

  • The certificate needs to be obtained and used
  • Front-end work
    • Create a view under settings which let's the admin add key/value pairs and then save it
  • Write Test for vault handler
  • Write documentation for the Vault

@Skarlso Skarlso changed the title ] [WIP] A secret vault storage with AES encryption using a certificate Jul 24, 2018
@codecov-io
Copy link

codecov-io commented Jul 24, 2018

Codecov Report

Merging #56 into master will increase coverage by 2.66%.
The diff coverage is 71.5%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #56      +/-   ##
==========================================
+ Coverage   53.61%   56.27%   +2.66%     
==========================================
  Files          14       16       +2     
  Lines        1218     1418     +200     
==========================================
+ Hits          653      798     +145     
- Misses        496      527      +31     
- Partials       69       93      +24
Impacted Files Coverage Δ
handlers/handler.go 84.5% <100%> (+0.92%) ⬆️
handlers/vault.go 59.37% <59.37%> (ø)
security/vault.go 76.51% <76.51%> (ø)
security/ca.go 76.23% <0%> (+1.98%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 3d8da40...5b28828. Read the comment docs.

}
defer os.Remove(vaultName)
v.Cert = []byte("test")
v.OpenVault()
Copy link
Member Author

Choose a reason for hiding this comment

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

This isn't needed here.

@Skarlso
Copy link
Member Author

Skarlso commented Jul 24, 2018

@michelvocks The view of the vault. :)

screen shot 2018-07-24 at 22 21 29

}

// OpenVault decrypts the contents of the vault and fills up a map of data to work with.
func (v *Vault) OpenVault() error {
Copy link
Member Author

Choose a reason for hiding this comment

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

Maybe call this LoadVault or GetVaultContent because it feels weird to use it in the handler.

}

// CloseVault encrypts data passed to the vault in a k/v format and saves it to the vault file.
func (v *Vault) CloseVault() error {
Copy link
Member Author

Choose a reason for hiding this comment

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

This definitely shloud be called SaveVault rather.

gaia.Cfg.Logger.Error("error initializing vault", "error", err.Error())
return c.String(http.StatusInternalServerError, err.Error())
}
v.Add(s.Key, []byte(s.Value))
Copy link
Member Author

Choose a reason for hiding this comment

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

I'm missing an open here so this is overwriting whatever is in the vault at the moment. Which brings me to rename the functions to make it more apparent how this needs to be used.

@Skarlso
Copy link
Member Author

Skarlso commented Jul 25, 2018

I need to write docs for the vault.

@Skarlso
Copy link
Member Author

Skarlso commented Jul 25, 2018

Working secret list.

screen shot 2018-07-25 at 07 57 50

@michelvocks
Copy link
Member

michelvocks commented Jul 25, 2018

Is the value shown as plain text? 😧
I think we should hide that.

@Skarlso
Copy link
Member Author

Skarlso commented Jul 25, 2018

@michelvocks for sure. It's for testing purposes only. :)

@Skarlso
Copy link
Member Author

Skarlso commented Jul 25, 2018

@michelvocks masked :)

screen shot 2018-07-25 at 21 43 06

screen shot 2018-07-25 at 21 42 58

@Skarlso Skarlso changed the title [WIP] A secret vault storage with AES encryption using a certificate A secret vault storage with AES encryption using a certificate Jul 25, 2018
@Skarlso
Copy link
Member Author

Skarlso commented Jul 25, 2018

Dooooooneee!

Vault empty:
screen shot 2018-07-25 at 23 35 23

Vault with secret:
screen shot 2018-07-25 at 23 35 42
screen shot 2018-07-25 at 23 35 50

Vault editing secret:
screen shot 2018-07-25 at 23 36 10

Vault deleting secret:
screen shot 2018-07-25 at 23 36 19

@Skarlso
Copy link
Member Author

Skarlso commented Jul 26, 2018

Ah, I need to write docs for this.

Copy link
Member

@michelvocks michelvocks left a comment

Choose a reason for hiding this comment

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

Good Job @Skarlso 🤗 Just a few remarks with things I do not understand 🤣

@@ -29,6 +29,14 @@ const state = {
icon: 'fa-cogs'
},
component: lazyLoading('settings', true)
},
Copy link
Member

Choose a reason for hiding this comment

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

Move vault up so it's over Settings in the menu list. Don't know why, but I'm used to find Settings at the last menu entry 🤗

},

changeSecret () {
// pre-validate
Copy link
Member

Choose a reason for hiding this comment

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

it might make sense to put the validation steps into another method so we can avoid some lines in both changeSecret and addSecret 😄

Copy link
Member Author

Choose a reason for hiding this comment

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

@michelvocks I suck at Javascript. How do I do that? :D

message: 'Secret has been successful changed.',
type: 'success'
})
this.selectSecret.newvalue = ''
Copy link
Member

Choose a reason for hiding this comment

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

you call close below which sets selectSecret to {}. Is this still needed?

Copy link
Member Author

Choose a reason for hiding this comment

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

didn't know that, thanks! :)

message: 'Secret has been successfully added.',
type: 'success'
})
this.selectSecret.value = null
Copy link
Member

Choose a reason for hiding this comment

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

Same here. You call below close which already sets selectSecret

s := new(updateSecret)
err := c.Bind(s)
if err != nil {
gaia.Cfg.Logger.Error("error reading secret", "error", err.Error())
Copy link
Member

Choose a reason for hiding this comment

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

This might get spammy in the logs when a user or another client is bored 😄. To be consistent with all other handlers, I think we should not log here.

return c.String(http.StatusInternalServerError, err.Error())
}
gaia.Cfg.Logger.Info("secret successfully added")
return c.String(http.StatusOK, "secret successfully added")
Copy link
Member

Choose a reason for hiding this comment

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

To be honest, I'm not really good at HTTP Status codes but this should be Created, right? 😆

Copy link
Member Author

Choose a reason for hiding this comment

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

Ops, absolutely.

}

// Setting up certificate key content
c, err := InitCA()
Copy link
Member

Choose a reason for hiding this comment

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

Don't create the CA here. It will be already created in the main.go file. You should pass this instance via Parameter to NewVault.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, but I'm always using NewVault, and Ca won't be something global, and it shouldn't be. A call to init, should just be idempotent, OR... be a singleton which still is a global 🤔 Not sure.

if err != nil {
return nil, err
}
data, err := ioutil.ReadFile(c.caKeyPath)
Copy link
Member

Choose a reason for hiding this comment

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

You should not access the private variable caKeyPath here. Use the method GetCACertPath.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ops, I mean to do that, huh.

// GetAll returns all keys and values in a copy of the internal data.
func (v *Vault) GetAll() []string {
m := make([]string, 0)
for k := range v.data {
Copy link
Member

Choose a reason for hiding this comment

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

What happens when someone accesses Add and in the same time GetAll? Isn't this a race condition?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, there should be a Read Lock here. :/ Thanks.


// Vault is a secret storage for data that gaia needs to store encrypted.
type Vault struct {
Path string
Copy link
Member

Choose a reason for hiding this comment

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

Is it on purpose that Path and Cert are global available?

Copy link
Member Author

Choose a reason for hiding this comment

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

You mean exported? Hum, haven't really thought about it, but you are right. They aren't used directly, so they can be private for only internal use. Thanks. :)

}

// UpdateSecret updates a secret using the vault.
func UpdateSecret(c echo.Context) error {
Copy link
Member Author

Choose a reason for hiding this comment

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

I don't like this duplication. I'm going to pull it into SetSecret which updates or Creates.

@Skarlso Skarlso force-pushed the secure_vault_file branch from 7c29152 to 0c12482 Compare July 27, 2018 04:26
README.rst Outdated
Security
--------

See the Documentation located here: |security-docs|.
Copy link
Member Author

Choose a reason for hiding this comment

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

this isn't linking the way I thought it would :D

README.rst Outdated
@@ -132,6 +132,11 @@ Gaia will compile it and add it to it's store for later execution.

Please find a bit more sophisticated example in our `go-example repo`_.

Security
--------
Copy link
Member

Choose a reason for hiding this comment

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

It should be = instead of -.

README.rst Outdated
Security
--------

See the Documentation located here: |security-docs|.
Copy link
Member

Choose a reason for hiding this comment

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

`security-docs`_

README.rst Outdated
.. |sh-pipeline-logs| image:: https://cdn.rawgit.com/michelvocks/6868118d0da06a422e69e453497eb30d/raw/51b4d6cbc3d86b1fe9531250db5456595423d9ec/pipeline_logs.png
:alt: gaia pipeline logs screenshot
:width: 650px

.. |sh-settings| image:: https://cdn.rawgit.com/michelvocks/6868118d0da06a422e69e453497eb30d/raw/142a2969c4d27d4135ef8f96213bb166009fda1e/settings.png
:alt: gaia settings screenshot
:width: 650px
.. |security-docs|
Copy link
Member

Choose a reason for hiding this comment

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

@Skarlso
Copy link
Member Author

Skarlso commented Jul 27, 2018

@michelvocks Battle tested the front-end with the Javascript modifications and all worked fine. Thanks for that. :)

Also updated the docs, everything should be cool now. Thanks for those fixes.

@Skarlso
Copy link
Member Author

Skarlso commented Jul 28, 2018

@michelvocks A little change... I slept on this and realised that we might want to change the vault's storage medium at some point to a database, or I don't know what.

In that case, I created the VaultStorer interface here: https://github.com/gaia-pipeline/gaia/pull/56/files#diff-6d277307688fa8de2b326d79a993e6b4R25

This made me able to mock the vault to a simple []byte storage medium in the tests, which is awesome. I'm going to do this in #61 for others as well. And also added some more coverage when the storage fails to write or read which is also nice.

@michelvocks
Copy link
Member

Awesome! 🤗
I think we shouldn't merge this PR as long as #24 isn't implemented. Currently, you can manage secrets but they are not useful. What do you think, @Skarlso?

@Skarlso
Copy link
Member Author

Skarlso commented Jul 28, 2018

I think that PR would be better off if this one is already in, since we could immediately utilise the functionality in #48. Which is blocked on the both of them. Also, I would rather start on the parameter stuff once this and #61 are in because they provide facilities and implementation details that could prove useful. Especially the Service Provider. In fact, I kind of want that in first, since it touches everything basically.

And if this is in, I can also make the vault part of the service provider.

At least that's what I'm thinking @michelvocks. :)

@michelvocks
Copy link
Member

Good point. Could you please squash your commits? Makes the history a bit cleaner. 🤗

Can you also have a look at the following change? https://github.com/gaia-pipeline/gaia/pull/60/files#diff-1e72a85e5dbe49ee4428eae35d6f1ee6R207
Instead of using the PKCS#1 format we need to use the PKCS#8 format. Does it affect this PR?

@Skarlso
Copy link
Member Author

Skarlso commented Jul 29, 2018

It does, yeah. But not that much and I agree with you. I'll do the changes. Also git can squash commits. You can select the squash and merge when merging, but I can do that if you wish ofc. :-)

Also, in fact I shloud have been using #8... Lazy me. :-/

@Skarlso
Copy link
Member Author

Skarlso commented Jul 29, 2018

So, I completely misunderstood this comment, and thought about something completely different. :D yay, me.

So as I wrote in Slack, but I'm writing it here too, what's happening with the certificate is, that I'm deriving a 32 bit password from it by base64-ing the content, and chopping it into a aes.BlockSize'd slice.

This means that the vault doesn't care what is in there. I'm also applying some padding in case of testing. The IV is generated and then used upon decryption too. It's marshalled into the encrypted data.

All in all it should be pretty secure. And it's AES 256 so it should be safe from brute forcing.

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.

3 participants