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

Add crio compatibility to WorkloadAttestor k8s - fixes #3183 #3242

Merged
merged 17 commits into from
Aug 1, 2022

Conversation

goergch
Copy link
Contributor

@goergch goergch commented Jul 13, 2022

  • Commit conforms to CONTRIBUTING.md?
  • Proper tests/regressions included?
  • Documentation updated?

Affected functionality

WorkloadAttestation Plugin k8s: compatibility with cri-o

Description of change
WorkloadAttestation Plugin k8s:

  • Adding cgroups regex to also match cgroup entries, that don't include a pod UI. That is explicitly currently crio, as no other container runtimes are known at the moment, that have the same behavior. The new regex therefore also explicitly checks for the "crio" string. It wasn't possible for me to combine the regex with the existing.
  • search through all pods and check, that the containerId found in cgroups, is is only present in one pod

Which issue this PR fixes
fixes #3183

Copy link
Collaborator

@MarcosDY MarcosDY left a comment

Choose a reason for hiding this comment

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

Thanks for this!!!

if item.UID != podUID {

// podUID can be empty, when cgroup contains only containerID
if item.UID != podUID && podUID != "" {
Copy link
Collaborator

Choose a reason for hiding this comment

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

On windows it is not possible to get podUID as it is happining in your use case, in order to solve that I created a function
what do you think about this:

if isNotPod(item.UID, podUID) {
   continue
}

and function:

func isNotPod(itemPodUID, podUID types.UID) bool {
       // podUID can be empty
       if podUID == ""  {
             return false
       }
       return item.UID != podUID
}
``

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 logic of the expression in line 198 is different: if podUI is set, only matching list Items are checked for equality.
I reformatted the condition to make it clearer

}, nil
if attestResponse != nil {
log.Warn("Two pods found with same container Id")
return nil, status.Error(codes.Aborted, "Two pods found with same container Id")
Copy link
Collaborator

Choose a reason for hiding this comment

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

errors must never start with uppercase on golang,
I'm not sure about using aborted or internal... as code, generally we use Internal in this cases

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not sure if we really need to make this verification, as long I know containerIDs are unique per node, even when a runtime is called to remove a container it only requires containerID.
In any case I'm ok keeping this validation

Copy link
Contributor Author

Choose a reason for hiding this comment

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

errors must never start with uppercase on golang,
I'm not sure about using aborted or internal... as code, generally we use Internal in this cases

done

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure if we really need to make this verification, as long I know containerIDs are unique per node, even when a runtime is called to remove a container it only requires containerID.
In any case I'm ok keeping this validation

I don't have a opinion on this. I just took the idea from @azdagron in #3183

@@ -598,6 +618,11 @@ func getPodUIDAndContainerIDFromCGroupPath(cgroupPath string) (types.UID, string
matches := cgroupRE.FindStringSubmatch(cgroupPath)
if matches != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I found than there are cases where CRIO-O is providing pods on cgroups.
With minikube using cri-o as runtime,

Preparing Kubernetes v1.23.3 on CRI-O 1.22.1 ...

I got pod on cgroup

9:devices:/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod561fd272_d131_47ef_a01b_46a997a778f3.slice/crio-030ded69d4c98fcf69c988f75a5eb3a1b4357e1432bd5510c936a40d7e9a1198.scope

And attestation works with that,

So instead of an if/else, what do you think about getting a list of regex, and validate cgroups against both regex?
and in case we get results from both make it fails?

in case of cgroupNoPodUidRE, maybe you can it always return 2 values, where the pod(first result) is always empty

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I implemented the list of regex. In addition I moved to named groups in the regex to be more flexible with the sequence of podUID and containerid

It's interesting to see, that the behavior in our system is caused by kubeedge and not by cri-o. Sadly I could not find an easy reason for this in kubeedge`s settings or source code.

Copy link
Collaborator

@MarcosDY MarcosDY left a comment

Choose a reason for hiding this comment

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

Great Job!! adding some additional comments

// Currently only cri-o in combination with kubeedge is known for this abnormaly.
regexp.MustCompile(`` +
// /crio-
`(?P<poduid>)[[:punct:]]crio[[:punct:]]` +
Copy link
Collaborator

Choose a reason for hiding this comment

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

mmm, I think it will cause that actual attestation against a regular CRI-O will stop working, because both regex will be true

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good point.
Regex in gelang is quite limited. It would need a negative lookahead to not match, when a poduid is present.
I introduced a "mustnotmatch" group for this.

pkg/agent/plugin/workloadattestor/k8s/k8s_posix.go Outdated Show resolved Hide resolved
pkg/agent/plugin/workloadattestor/k8s/k8s_test.go Outdated Show resolved Hide resolved
pkg/agent/plugin/workloadattestor/k8s/k8s_posix.go Outdated Show resolved Hide resolved
pkg/agent/plugin/workloadattestor/k8s/k8s_posix.go Outdated Show resolved Hide resolved
pkg/agent/plugin/workloadattestor/k8s/k8s_posix.go Outdated Show resolved Hide resolved
}, nil
if attestResponse != nil {
log.Warn("Two pods found with same container Id")
return nil, status.Error(codes.Internal, "two pods found with same container Id")
Copy link
Collaborator

Choose a reason for hiding this comment

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

can you add an unit test for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

TestAttestFailDuplicateContainerId already does this

func reSubMatchMap(r *regexp.Regexp, str string) map[string]string {
match := r.FindStringSubmatch(str)
var subMatchMap map[string]string = nil
if match != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

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

an early return maybe can simplify this code:

match := r.FindStringSubmatch(str)
if match == nil {
   return nil
}
subMatchMap = make(map[string]string)
for i, name := range r.SubexpNames() {
	if i != 0 {
		subMatchMap[name] = match[i]
	}
}
return subMatchMap 

if matches != nil {
if matchResults != nil {
log.Printf("More than one regex matches for cgroup %s", cgroupPath)
return "", "", false
Copy link
Collaborator

Choose a reason for hiding this comment

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

can you add an unit test to verify that regular CRI-O (for example the one I put from minikube) still works?

Copy link
Collaborator

@MarcosDY MarcosDY left a comment

Choose a reason for hiding this comment

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

Changes looks good, but you will need to solve conflicts and solve DCO issues, you will need to signoff all commits

goergch and others added 11 commits July 26, 2022 07:20
Signed-off-by: Christian Görg <christian.goerg@trumpf.com>
* Add integration test for CRD mode

Signed-off-by: Marcos Yacob <marcos.yacob@hpe.com>
Signed-off-by: Christian Görg <christian.goerg@trumpf.com>
)

Bumps [github.com/open-policy-agent/opa](https://github.com/open-policy-agent/opa) from 0.42.0 to 0.42.1.
- [Release notes](https://github.com/open-policy-agent/opa/releases)
- [Changelog](https://github.com/open-policy-agent/opa/blob/main/CHANGELOG.md)
- [Commits](open-policy-agent/opa@v0.42.0...v0.42.1)

---
updated-dependencies:
- dependency-name: github.com/open-policy-agent/opa
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: Christian Görg <christian.goerg@trumpf.com>
Also pulled in CHANGELOG for 1.3.2 and updated upgrade IT

Signed-off-by: Andrew Harding <aharding@vmware.com>
Signed-off-by: Christian Görg <christian.goerg@trumpf.com>
* Remove webhook mode from k8s-workload-registrar

This was deprecated in 1.3.0. Removing for 1.4.0.

Signed-off-by: Andrew Harding <aharding@vmware.com>

* Address PR comments

Signed-off-by: Andrew Harding <aharding@vmware.com>
Signed-off-by: Christian Görg <christian.goerg@trumpf.com>
checks cgroups against regex array

Signed-off-by: Christian Görg <christian.goerg@trumpf.com>
Co-authored-by: Marcos Yacob <marcos.yacob@hpe.com>
Signed-off-by: Christian Görg <christian.goerg@trumpf.com>
Co-authored-by: Marcos Yacob <marcos.yacob@hpe.com>
Signed-off-by: Christian Görg <christian.goerg@trumpf.com>
Co-authored-by: Marcos Yacob <marcos.yacob@hpe.com>
Signed-off-by: Christian Görg <christian.goerg@trumpf.com>
Co-authored-by: Marcos Yacob <marcos.yacob@hpe.com>
Signed-off-by: Christian Görg <christian.goerg@trumpf.com>
Signed-off-by: Christian Görg <christian.goerg@trumpf.com>
Signed-off-by: Christian Görg <christian.goerg@trumpf.com>
@goergch
Copy link
Contributor Author

goergch commented Jul 26, 2022

Changes looks good, but you will need to solve conflicts and solve DCO issues, you will need to signoff all commits

main is now freshly merged into the pull request and every commit signed off. Thanks for the productive review @MarcosDY

Copy link
Collaborator

@MarcosDY MarcosDY left a comment

Choose a reason for hiding this comment

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

Looks great!! just a pretty simple comment, and there are 2 lint failing

for _, item := range list.Items {
item := item
if isNotPod(item.UID, podUID) {
if podUID != "" && isNotPod(item.UID, podUID) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

this podUID != "" may go into isNotPod() if not it can affect windows code, in case in a future we are able to get podUID on windows instances

Fixes lint

Signed-off-by: Christian Görg <christian.goerg@trumpf.com>
Copy link
Collaborator

@MarcosDY MarcosDY left a comment

Choose a reason for hiding this comment

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

lgtm!

@MarcosDY MarcosDY merged commit 1d447fb into spiffe:main Aug 1, 2022
@azdagron azdagron added this to the 1.4.0 milestone Aug 1, 2022
stevend-uber pushed a commit to stevend-uber/spire that referenced this pull request Oct 16, 2023
…piffe#3242)

- Adding cgroups regex to also match cgroup entries, that don't include a pod UI. That is explicitly currently crio, as no other container runtimes are known at the moment, that have the same behavior. The new regex therefore also explicitly checks for the "crio" string. It wasn't possible for me to combine the regex with the existing.
- search through all pods and check, that the containerId found in cgroups, is is only present in one pod
Signed-off-by: Christian Görg <christian.goerg@trumpf.com>

Signed-off-by: Christian Görg <christian.goerg@trumpf.com>
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.

Incompatibility WorkloadAttestation k8s and Kubeedge k8s
3 participants