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

Create AES128 and AES256 encryption for parameters #4756

Merged
merged 11 commits into from
Mar 11, 2020

Conversation

mcdan
Copy link
Member

@mcdan mcdan commented Nov 26, 2019

Encrypt just before putting into the db
Decrypt only right before invoking the action

Description

This will encrypt the default params for actions and packages at rest in the DB.

Currently implemented AES128 and 256 encryption, although 256 needs some work regarding packaging.

Related issue and scope

My changes affect the following components

  • API
  • Controller
  • Message Bus (e.g., Kafka)
  • Loadbalancer
  • Invoker
  • Intrinsic actions (e.g., sequences, conductors)
  • Data stores (e.g., CouchDB)
  • Tests
  • Deployment
  • CLI
  • General tooling
  • Documentation

Types of changes

  • Bug fix (generally a non-breaking change which closes an issue).
  • Enhancement or new feature (adds new functionality).
  • Breaking change (a bug fix or enhancement which changes existing behavior).

Checklist:

  • I signed an Apache CLA.
  • I reviewed the style guides and followed the recommendations (Travis CI will check :).
  • I added tests to cover my changes.
  • My changes require further changes to the documentation.
  • I updated the documentation where necessary.

protected[entity] case class ParameterValue protected[entity] (private val v: JsValue, val init: Boolean) {
protected[entity] case class ParameterValue protected[entity] (private val v: JsValue,
val init: Boolean,
val e: JsValue = JsNull) {
Copy link
Member

@rabbah rabbah Nov 29, 2019

Choose a reason for hiding this comment

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

Why not just store the encrypted value in v and a boolean to indicate it's encrypted?

Copy link
Member Author

Choose a reason for hiding this comment

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

Adding which scheme would allow someone later to migrate from scheme A to B if an issue surfaces in the former.

Copy link
Member

Choose a reason for hiding this comment

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

how about something better than e - secret, or encrypted or something else?

Copy link
Member

Choose a reason for hiding this comment

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

should e be an option type (which would allow omission) - similarly would it be simpler if when present this value is meaningful (a string or bool and not null).

at this point i'm not sure what values this takes on yet.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yup, I went with your suggestion and locked down what the encryption schemes are allowed to do.

@mcdan
Copy link
Member Author

mcdan commented Dec 4, 2019

Can I get a WIP tag on this PR?

@rabbah rabbah added the wip label Dec 4, 2019
@mcdan mcdan closed this Dec 12, 2019
@mcdan mcdan reopened this Dec 12, 2019
@mcdan mcdan force-pushed the mcdan/param-encrypt branch 2 times, most recently from 8726e0f to 95f7693 Compare December 12, 2019 21:03
@rabbah rabbah marked this pull request as ready for review December 12, 2019 22:06
@mcdan mcdan force-pushed the mcdan/param-encrypt branch 2 times, most recently from 0b37d1f to fea10b9 Compare December 13, 2019 20:53
@mcdan mcdan force-pushed the mcdan/param-encrypt branch 2 times, most recently from 0b1d895 to 132fcd6 Compare January 3, 2020 21:33
Encrypt just before putting into the db
Decrypt only right before invoking the action
@mcdan mcdan force-pushed the mcdan/param-encrypt branch 3 times, most recently from 5c78b26 to 94ff4bd Compare January 9, 2020 21:09
Broke reading the kafka protocol into a new method to keep the
strict parsing of the scheme intact.
Use only base64 encoded keys.
@codecov-io
Copy link

codecov-io commented Jan 9, 2020

Codecov Report

Merging #4756 into master will decrease coverage by 41.34%.
The diff coverage is 42.18%.

Impacted file tree graph

@@             Coverage Diff             @@
##           master    #4756       +/-   ##
===========================================
- Coverage    85.1%   43.75%   -41.35%     
===========================================
  Files         190      198        +8     
  Lines        8578     8987      +409     
  Branches      601      621       +20     
===========================================
- Hits         7300     3932     -3368     
- Misses       1278     5055     +3777
Impacted Files Coverage Δ
...rg/apache/openwhisk/core/entity/WhiskPackage.scala 30.15% <100%> (-66.62%) ⬇️
...org/apache/openwhisk/core/entity/WhiskAction.scala 67.75% <100%> (-23.5%) ⬇️
.../openwhisk/core/containerpool/ContainerProxy.scala 67.54% <100%> (-24.43%) ⬇️
.../scala/org/apache/openwhisk/core/WhiskConfig.scala 85.92% <100%> (-8.86%) ⬇️
...he/openwhisk/core/entity/ParameterEncryption.scala 29.31% <29.31%> (ø)
...a/org/apache/openwhisk/core/entity/Parameter.scala 59.18% <46.77%> (-31.39%) ⬇️
...pache/openwhisk/http/LenientSprayJsonSupport.scala 0% <0%> (-100%) ⬇️
...core/database/cosmosdb/RxObservableImplicits.scala 0% <0%> (-100%) ⬇️
...ore/containerpool/kubernetes/WhiskPodBuilder.scala 0% <0%> (-100%) ⬇️
...nwhisk/core/database/cosmosdb/CosmosDBConfig.scala 0% <0%> (-100%) ⬇️
... and 151 more

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 d9e4c10...363e2f4. Read the comment docs.

@mcdan
Copy link
Member Author

mcdan commented Jan 10, 2020

WIP can be removed from this it seems ready to go.

@rabbah rabbah added review Review for this PR has been requested and yet needs to be done. and removed wip labels Jan 10, 2020
@rabbah rabbah self-requested a review January 10, 2020 15:19
case true => Some("init" -> p._2.init.toJson)
case _ => None
}
val encrypt = p._2.encryption match {
Copy link
Member

Choose a reason for hiding this comment

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

can you add a comment what the valid/possible values of encryption are?

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 added some better tests and took your advice to tighten up this field. At first I though this might be where I stuck the IVs or other stuff the encryption scheme wanted to hold on to but I ended up just sticking that inside the raw value given that it's already a byte array.

@@ -129,7 +148,7 @@ protected[core] class Parameters protected[entity] (private val params: Map[Para

/**
* A ParameterName is a parameter name for an action or trigger to bind to its environment.
* It wraps a normalized string as a value type.
* It wraps a normalized string as a valueread type.
Copy link
Member

Choose a reason for hiding this comment

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

typo?

case _ => Some("encryption" -> p._2.encryption.toJson)
}
// Have do use this slightly strange construction to get the json object order identical.
JsObject(ListMap() ++ encrypt ++ init ++ Map("key" -> p._1.name.toJson, "value" -> p._2.value.toJson))
Copy link
Member

Choose a reason for hiding this comment

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

I do not understand what's happening here.

Copy link
Member Author

Choose a reason for hiding this comment

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

There were tests which I did not want to alter that checked the order of the values in the JSObject. To keep them working correctly I needed to add each property in a specific way. To my mind those tests shouldn't rely on the ordering of what is really a map but with JSON that is somewhat unclear around the ordering guarantee.

Copy link
Member

Choose a reason for hiding this comment

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

Agree that ordering shouldn't matter in general - without inspecting those tests, I wonder if the tests you're referring to are actually looking at precedence order (which properties should win when there are conflicts between two maps).

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 double checked by mixing up the append order and this assert fails: https://github.com/apache/openwhisk/blob/master/tests/src/test/scala/org/apache/openwhisk/core/entity/test/SchemaTests.scala#L708
As it asserts the string equality of the json output. Given that I was hesitant to alter its order.

Copy link
Member

Choose a reason for hiding this comment

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

Fixed here 845241a.

protected[entity] case class ParameterValue protected[entity] (private val v: JsValue, val init: Boolean) {
protected[entity] case class ParameterValue protected[entity] (private val v: JsValue,
val init: Boolean,
val e: JsValue = JsNull) {
Copy link
Member

Choose a reason for hiding this comment

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

how about something better than e - secret, or encrypted or something else?

protected[entity] case class ParameterValue protected[entity] (private val v: JsValue, val init: Boolean) {
protected[entity] case class ParameterValue protected[entity] (private val v: JsValue,
val init: Boolean,
val e: JsValue = JsNull) {
Copy link
Member

Choose a reason for hiding this comment

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

should e be an option type (which would allow omission) - similarly would it be simpler if when present this value is meaningful (a string or bool and not null).

at this point i'm not sure what values this takes on yet.

Copy link
Member

@rabbah rabbah left a comment

Choose a reason for hiding this comment

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

Thanks @mcdan for the clarifications - looking through the rest of the PR and tests.

case _ => Some("encryption" -> p._2.encryption.toJson)
}
// Have do use this slightly strange construction to get the json object order identical.
JsObject(ListMap() ++ encrypt ++ init ++ Map("key" -> p._1.name.toJson, "value" -> p._2.value.toJson))
Copy link
Member

Choose a reason for hiding this comment

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

Agree that ordering shouldn't matter in general - without inspecting those tests, I wonder if the tests you're referring to are actually looking at precedence order (which properties should win when there are conflicts between two maps).

@mcdan mcdan force-pushed the mcdan/param-encrypt branch 3 times, most recently from a046bca to 071671a Compare February 3, 2020 16:48
@mcdan
Copy link
Member Author

mcdan commented Feb 13, 2020

Not sure why travis isn't updating this but the build is green for this: https://travis-ci.org/apache/openwhisk/builds/646477660
@rabbah is this okay to get merged?

@rabbah
Copy link
Member

rabbah commented Feb 13, 2020

Thanks for the nudge. Will review the newest commits.

@mcdan
Copy link
Member Author

mcdan commented Feb 14, 2020

No worries we have this running now on our prod cluster now so it's at least working.

val byteBuffer = ByteBuffer.wrap(Base64.getDecoder.decode(cipherMessage))
val ivLength = byteBuffer.getInt
if (ivLength != ivLen) {
throw new IllegalArgumentException("invalid iv length")
Copy link
Member

Choose a reason for hiding this comment

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

decryption occurs in the invoker - this will therefore fail in the container proxy and we should add a test to cover failure and make sure the activation cleans up cleanly.

Copy link
Member

@rabbah rabbah left a comment

Choose a reason for hiding this comment

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

I have gone through this PR as careful as I can. Once this PR is merged, I have some enhancements and refactoring which I'll follow up with.

After this PR, when parameter encryption is turned on, the parameters on action update and package update are encrypted using the current scheme. When an action or package is retrieved, the parameters are not decoded

Triggers parameters are currently not locked. This should be considered as a subsequent PR.

response.updated.toEpochMilli should be > dummyUpdated
}
}
// it should "ignore updated field when updating action" in {
Copy link
Member

Choose a reason for hiding this comment

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

does this test fail?

@rabbah
Copy link
Member

rabbah commented Mar 9, 2020

@mcdan given that github will reattribute the commit I squash and commit, I defer to you to rebase, and fix up the commit message/merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
review Review for this PR has been requested and yet needs to be done.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants