-
Notifications
You must be signed in to change notification settings - Fork 486
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
agent/workloadattestor: Add docker plugin #687
Conversation
3c9bc8f
to
ea48a32
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.
parts := strings.Split(cgroup.GroupPath, "/") | ||
|
||
if len(parts) <= p.cgroupContainerIndex+1 { | ||
log.Printf("docker entry found, but without container id: %v", cgroup.GroupPath) |
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.
nit: Log messages should be capitalized. Also, might be a bit clearer s/without container id/is missing the container id/
} | ||
|
||
if !hasDockerEntries { | ||
return nil, fmt.Errorf("workloadattestor/docker: no cgroup entries found with prefix %q", p.cgroupPrefix) |
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 used to have logging like this in the k8s attestor, but ended up removing it because it would cause the agent to log errors when trying to attest non-k8s workloads. Generally speaking, I think we should support the mix-and-match case well and expect that maybe some dockerized workloads will call us, and some others will call us too... in that vein, perhaps we should not log or return an error here? Curious to hear thoughts on this point
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.
Ah okay, I noticed that but wasn't sure of the reason. Agree with this reasoning and updated to reflect
return &spi.ConfigureResponse{ErrorList: []string{err.Error()}}, err | ||
} | ||
p.cgroupPrefix = config.CgroupPrefix | ||
p.cgroupContainerIndex = config.CgroupContainerIndex |
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.
Do we want to set the defaults on these here?
| docker_socket_path | The location of the docker daemon socket (default: "unix:///var/run/docker.sock" on unix). | | ||
| docker_version | The API version of the docker daemon (default: "1.25"). | ||
| cgroup_prefix | The cgroup prefix to look for in the cgroup entries (e.g. "/docker"). | | ||
| cgroup_container_index | The index within the cgroup path where the container ID should be found (default: 0). | |
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.
IMO it is desirable to limit the number of knobs available to users wherever possible... otherwise, they tend to tweak things inappropriately and end up with either misconfigured or broken software, sometimes without even knowing. In that vein, I'd vote to leave cgroup_prefix
and cgroup_container_index
undocumented... I don't think they are very likely to change... If someone comes to us with a broken attestor we can ask them to tweak these undocumented values, or if an operator finds them in the code, then the assumption is that they know what they are doing
If we remove these configurables from the documentation, then we can also remove the Cgroup entry
section below
| cgroup_container_index | The index within the cgroup path where the container ID should be found (default: 0). | | ||
|
||
Since selectors are created dynamically based on the container's docker labels, there isn't a list of known selectors. | ||
Instead, all of the container's labels are used in creating the list of selectors. |
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 don't think this applies any longer?
| Selector | Value | | ||
| -------- | ----- | | ||
| docker:label:abc | The value of the docker label `abc` | | ||
| docker:label:xyz | The value of the docker label `xyz` | |
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.
nit: I know that this is taken from the k8s workload attestor docs, but I think separating by selector and value is confusing to users. Even though the difference between type and value is distinguished internally, we don't really surface that very strongly in the CLI tools. I'd suggest a table like this one instead: https://github.com/spiffe/spire/blob/master/doc/plugin_server_nodeattestor_k8s_sat.md
If a workload container is started with `docker run --label com.example.name=foo [...]`, then its workload selector will be: | ||
``` | ||
type: "docker:label" | ||
value: "com.example.name=foo" |
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.
=
or :
?
Similar nit here on selector type/value
conf/agent/agent.conf
Outdated
plugin_data { | ||
cgroup_container_index = 3 | ||
cgroup_prefix = "" | ||
labels = [""] |
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 we can remove labels
and possibly the other two as well if we decide to leave them undocumented
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.
Looking great :) Just a couple of small nits...
) | ||
|
||
const ( | ||
_selectorType = "docker" |
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.
nit: package consts should be camelCase
w/o the leading underscore.
|
||
// Parse HCL config payload into config struct | ||
config := &dockerPluginConfig{} | ||
hclTree, err := hcl.Parse(req.Configuration) |
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.
nit: hcl can be parsed and decoded in a single step via hcl.Decode(config, req.Configuration)
config := &dockerPluginConfig{} | ||
hclTree, err := hcl.Parse(req.Configuration) | ||
if err != nil { | ||
return &spi.ConfigureResponse{ErrorList: []string{err.Error()}}, err |
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 know this was likely a pattern followed from other plugins, but we should just return nil, err
here. The ErrorList stuff isn't used and gRPC ignores the returned response anyway if an error is returned. I've been meaning to clean up the plugins.... :)
Signed-off-by: R. Tyler Julian <tjulian@uber.com>
ea48a32
to
3fca261
Compare
Okay I've made the recommended changes. Sorry I had to force push to rebase onto master and signoff correctly, so some of the history is lost. Anyway, one more thing I wanted to discuss: Regarding the docker dependency, the library has a weird versioning/support story. I tried including the latest version,
I've run into logrus import errors too many times to care to debug this lol. The current state of this PR pins to |
Signed-off-by: R. Tyler Julian <tjulian@uber.com>
Hmm. I pulled down your branch and ran |
Ah okay yeah I'm new to |
Here's an example of what (4) would look like: APTy/spire@tj/docker-attestor...APTy:tj/docker-attestor-2. It's probably missing some things like client version negotiation, but it's not too complex to create the core functionality ourselves. |
Signed-off-by: R. Tyler Julian <tjulian@uber.com>
My opinion is that since github.com/docker/docker/client is from the official docker repo, we should probably just pin to latest master (assuming that it works). I think enough has changed in 1.5 years that using the old release will be problematic from a dependency standpoint (as you have discovered). I'd be totally for vendoring or writing our own if this was some problematic one-off library, but since it is the official repo, I'm pretty comfortable just using it. Dunno if @evan2645 has other thoughts... |
Signed-off-by: R. Tyler Julian <tjulian@uber.com>
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.
Awesome. Thanks @APTy!
Pull Request check list
Affected functionality
Adds a docker-based workload attestor that enables selectors based on docker labels and the container's image id.
TODO