-
Notifications
You must be signed in to change notification settings - Fork 89
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
[Attestation Service] Change the API of CoCo-AS #240
[Attestation Service] Change the API of CoCo-AS #240
Conversation
ff25252
to
adadb18
Compare
tee: to_grpc_tee(tee).into(), | ||
evidence: STANDARD.encode(attestation.tee_evidence), | ||
runtime_data, | ||
init_data: vec![], |
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.
cc @mkulke You might be interested in this -- This is the KBS side code that does not leverage the ability of the initdata verafication in this PR.
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.
LGTM. Thanks! @Xynnn007
adadb18
to
d4dbd55
Compare
we may also need |
Nonce is something that will be bound to the report data. This API now gives a general parameter |
AFAIUI, the AS cannot generate "expected report data" based on |
You are right. This api is now for user who knows the materials to calculate the report data. We can add an extra API, which will give a nonce to the caller to get evidence. Then the user can call this attestation API. |
I'm still reviewing, but the attestation requester should not be passing |
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 think this is a step in the right direction but needs some more thought.
It's not secure to mix claims attested through runtime data (like tee-pubkey, nonce) with "custom claims" which are unattested and user controlled. So we really need to impose some structure on runtime data (like a json dictionary) that can be included in the attested token separately from any user supplied data.
Custom claims should instead be a "nonce" supplied by the user to be included in the attestation token.
let runtime_data = request | ||
.runtime_data | ||
.iter() | ||
.map(|data_item| { | ||
STANDARD | ||
.decode(data_item) | ||
.map_err(|e| Status::aborted(format!("base64 decode runtime data: {e}"))) | ||
}) | ||
.collect::<std::result::Result<Vec<Vec<u8>>, Status>>()?; | ||
|
||
let init_data: Vec<Vec<u8>> = request | ||
.init_data | ||
.iter() | ||
.map(|data_item| { | ||
STANDARD | ||
.decode(data_item) | ||
.map_err(|e| Status::aborted(format!("base64 decode init data: {e}"))) | ||
}) | ||
.collect::<std::result::Result<Vec<Vec<u8>>, Status>>()?; |
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.
Why array of base64 strings? I think these should just be base64 strings. We also need to document the fact that parameters are base64 encoded and document which base64 encoding is used in README.md. In remote APIs it is most commonly URL_SAFE_NO_PAD
, not STANDARD
.
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.
It is embarassing. If we does not use array, it will be difficult to distinguish an "empty runtime data" and "no runtime data" by only one parameter. It would be better to keep as-is and let me add more document about this.
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.
are there optional parameters in grpc? i care more about how this works for a JSON http API, where we can have can have:
"runtime_data": {}
or
"runtime_data": { "data": "" }
or skip passing runtime_data.
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.
In gRPC, optional
key word is replaced by repeated
. In on-going rest CoCo AS we will:
- If no
"runtime_data"
field is in the request body. We do not check - If
"runtime_data": {}
field is given. we do the check, byhash(b"")
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.
if we stick to an array it would be more like:
- no "runtime_data" or
"runtime_data": []
- we don't check "runtime_data": [""]
we checkhash(b"")
.
@jepio The key point is that the returned attestation token will have information about the policy ids that are used to check against the evidence. Current AS only has a fixed policy and cannot choose a specific one from API. Doea this make sense? |
I see. I now see that ITA also allows the user the option to pass the policy in a similar way. Why don't we do it same way as well:
|
This is a great point. I think this is related to how policies are indexed. Currently we only have OPA as policy engine and the regos are stored in filesystem so we directly retrieve them with the file name. In this PR, I added the policy digest into the result JWT as you suggested to ensure the integrity of policy recorded in the JWT. However how to specify which policy should be used might be another topic, as it is related to how it is stored. We can promote this in another PR. wdyt? |
It is a good idea that we should have a runtime data format/spec like undergoing initdata. This could help us to leverage report_data field in a more standard way. A json map would help both protect the integrity and embed into extra claims. But for custormized claims, my idea is that this would give ability to the user to embed some extra context information without integrity protection. Whether to use such claims is determined by the consumer of the JWT. In CoCo-AS/KBS model, the attestation requester and JWT consumer both are KBS, so it is secure for KBS itself to leverage the pub-key fields inside the claims. I'm not sure whether both should be supported (with/without integrity protection), but seems that we should.
From the perspective of opposing server replay attack, this is worth doing. |
8f48dd8
to
a9ac1f5
Compare
Update the PR due to @jepio 's suggestions. This is still under reviewing. I added some more documents and the examples for CoCoAS gRPC. |
}, | ||
"evaluation-reports": [ | ||
{ | ||
"evaluation-result": "{\"allow\":true}", |
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.
does the evaluation result have to be a string? can't it be:
"evaluation-result": {
"allow": true
}
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.
This is the raw string output by OPA when using the default_policy.rego
. I am afraid that we cannot assume what the result will look like. It is decided by the rego.
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.
we can specify what it needs to look like to be valid. and besides: the code already parses the OPA output and checks that it matches this structure.
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.
Let me parse the output directly as a JSON object. I think the document of policies can be added in another PR that also can promote the policy storage.
I think we need to address this before. We can't change the token format every week because without stability we won't see adoption. We should not be leaking the fact that policies are stored in filesystem into our token API - in a cloud deployment of CoCo AS the backend storage will be blob storage. So I think we need policy management APIs like ITA (https://docs.trustauthority.intel.com/main/restapi/restapi-policy-management.html). When a user registers a policy they need to either pass a UUID or the API returns a UUID. And then this UUID would be passed with the attestation request. WDYT? |
No, it's not secure. Anyone can request a CoCo-AS token passing an arbitrary public key in "custom claims", also one not stored in a TEE and then pass that token to CoCo KBS. So "runtime-claims" (attested through a REPORTDATA mechanism) need to be separated from arbitrary "custom claims" in the token. Anything else can't be trusted by consumers. |
attestation-service/attestation-service/src/policy_engine/opa/mod.rs
Outdated
Show resolved
Hide resolved
a9ac1f5
to
115e6cc
Compare
@jepio Updated the PR. Added a separate commit where I use |
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.
This looks good.
A few questions:
Do you think it would be useful if we had some kind of default policy? This could be set per-AS and evaluated on every request. It might help simplify the process of provisioning policies for simple use cases.
How does reference data fit into this? It looks like reference values aren't set via the attestation request or reported in the attestation results. The same policy could have very different results with different reference values.
if !allow { | ||
bail!("Untrusted TEE evidence") | ||
bail!("TEE evidence does not pass policy {policy_id}, reason: {policy_res}"); |
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'm not sure this is the best way to handle this. It might be better to return a token that says that a policy has not passed evaluation. It's a bit hard to know. Maybe that would increase the complexity of the KBS.
If we stick with this approach we should make sure to document it well for clients who are trying to write policies.
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.
In the initial implementation I embed the policy validation results into the result token. Suggested by @jepio #240 (comment) I think it is right that if any policy fails to check, the verifiecation should fail.
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.
@Xynnn007 I think the meaning of specifying multiple policy IDs is to introduce more flexibility in the attestation result report. Therefore, it may not be a good idea to force all policies to pass on the AS side.
The requirement logic for proving a request may be varied. For example, some users may write different policies to verify different field contents, so that they want all specified policies to pass. However, other users may write different policies to correspond to different TEE software versions, so they hope that at least one policy can be passed.
The requirement logic like the above should be decided by the user himself, and the attestation result report should truthfully reflect the verification content of each policy, rather than forcing each specified policy to pass.
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.
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.
Yeah I think either one is fine. The first option sort of implies that the AS policies are going to return binary values, which isn't necessarily the case. The second option will likely increase the complexity of the KBS policies. I guess we can pick one, merge it, and see how we feel about it down the road.
Yes. I have already added this here. That means if no policy id is set, gRPC CoCo-AS will use the "default" one. This was not implementation inside the library as I think it is a specific behavior of the service rather than generic lib. On the KBS side, we can add an optional parameter inside the launch configuration to specify the policy. If not specified, a hardcode default one will be used.
Reference data seems a design challlenge. Reasons
But overall, I agree with you that attestation token should have the reference data information inside. So let just temporarily ignore how 1 & 2 are handled, and just try to fix the token format, s.t. another field containing reference data information that was used when doing verification. wdyt? |
Due to confidential-containers#240 (comment) any claims inside the attestation token should be ensured integrity by binding the digest into the HW evidence. This commit supports both structured and raw init/runtime data to check against the binding of that in evidence. Now two kinds of binding check are supported: 1. Raw data. CoCo-AS can help to check if the runtime/init data field is the same as the given raw data. 2. Structured data. CoCo-AS can help to check if the digest of the given JSON object (with keys in every layer reordered in alphabet) is the same as the runtime/init data. If matched, the result attestation token will contain the JSON object as customized claims. Signed-off-by: Xynnn007 <xynnn@linux.alibaba.com>
115e6cc
to
f41223e
Compare
f41223e
to
157ecc4
Compare
Rebased and update the PR with the new API. @jepio @fitzthum @jialez0 a decision left: whether the token can be provisioned without passing all OPA policies @mythi Added the KBS side check for confidential-containers/guest-components#366 here |
157ecc4
to
29ffabd
Compare
|
Before this commit, the API of Attestation-Service lib is coupled with KBS protocol. Also, not all functionalities of verifier driver are used, including checking the binding of initdata hash and runtime data hash. This commit will help to only have attestation related parameters in this API. Signed-off-by: Xynnn007 <xynnn@linux.alibaba.com>
Signed-off-by: Xynnn007 <xynnn@linux.alibaba.com>
After update the API of attestation-service lib, gRPC service also needs to be updated. Before this commit, the API of gRPC AS is coupled with KBS protocol. It is needed for a user to just use CoCo-AS to do some verification work without coperating with KBS. Signed-off-by: Xynnn007 <xynnn@linux.alibaba.com>
New CoCo-AS API will decouple KBS protocol semantics. Also, this commit changes the hashed materials when connecting to CoCo-AS. Before this commit, only k_mod and k_exp of tee-pubkey field are protected integrity when doing remote attestation. The `kty` and `alg` field of the tee-pubkey are ignored. Signed-off-by: Xynnn007 <xynnn@linux.alibaba.com>
Fixed the wrong guides to build a gRPC CoCo-AS. Also update the new format of attestation-token. Signed-off-by: Xynnn007 <xynnn@linux.alibaba.com>
Signed-off-by: Xynnn007 <xynnn@linux.alibaba.com>
d130c1b
to
0cd92cf
Compare
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.
LGTM
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.
lgtm. I'm ok with either of the approaches (always release token or only release token when all policies pass) until we find some problem.
This PR will refactor the CoCo-AS furthermore, which will help to let CoCo-AS run as a seperate attestation-service without any coupling with KBS.
The API of CoCo AS will be definitely not related to KBS protocol. In this PR, CoCo-AS gRPC service will have the following API
Close #177
Related to #217
cc @jialez0