cyberark / conjur

CyberArk Conjur automatically secures secrets used by privileged users and machine identities
https://conjur.org
Other
780 stars 124 forks source link

Add ascii flow diagram to Kubernetes authenticator #1610

Closed izgeri closed 4 years ago

izgeri commented 4 years ago

It can be hard for newcomers to understand the authn-k8s flow, so it might be useful to add an ascii flow diagram (like we've done with Secretless here, for example) to the top of the main authn-k8s file (eg this one).

izgeri commented 4 years ago

Possible flow (not 100% sure this is correct):

+-----+                                               +-----+                                                   +---------+
| App |                                               | K8s |                                                   | Conjur  |
+-----+                                               +-----+                                                   +---------+
   |                                                     |                                                           |
   | Inject client certificate request                   |                                                           |
   |---------------------------------------------------------------------------------------------------------------->|
   |                                                     |                                                           |
   |                                                     |                          Validate pod exists in namespace |
   |                                                     |<----------------------------------------------------------|
   |                                                     |                                                           |
   |                                                     |      Validate application identity resource exists in K8s |
   |                                                     |<----------------------------------------------------------|
   |                                                     |                                                           |
   |                                                     |                                   Error (if one occurred) |
   |<----------------------------------------------------------------------------------------------------------------|
   |                                                     |                                                           |
   |                                                     |      Run "kubectl exec" to install the signed certificate |
   |                                                     |<----------------------------------------------------------|
   |                                                     |                                                           |
   |    Install the signed Conjur certificate in the pod |                                                           |
   |<----------------------------------------------------|                                                           |
   |                                                     |                                                           |
   |                                                     | Error (if one occurred)                                   |
   |                                                     |---------------------------------------------------------->|
   |                                                     |                                                           |
   | Authenticate request                                |                                                           |
   |---------------------------------------------------------------------------------------------------------------->|
   |                                                     |                                                           |
   |                                                     |                          Validate pod exists in namespace |
   |                                                     |<----------------------------------------------------------|
   |                                                     |                                                           |
   |                                                     |      Validate application identity resource exists in K8s |
   |                                                     |<----------------------------------------------------------|
   |                                                     |                                                           |
   |                                                     |                                Return Conjur access token |
   |<----------------------------------------------------------------------------------------------------------------|
   |                                                     |                                                           |

this was generated at https://textart.io/sequence using the source:

object App K8s Conjur
App->Conjur: Inject client certificate request
Conjur->K8s: Validate pod exists in namespace
Conjur->K8s: Validate application identity resource exists in K8s
Conjur->App: Error (if one occurred)
Conjur->K8s: Run "kubectl exec" to install the signed certificate
K8s->App: Install the signed Conjur certificate in the pod
K8s->Conjur: Error (if one occurred)
App->Conjur: Authenticate request
Conjur->K8s: Validate pod exists in namespace
Conjur->K8s: Validate application identity resource exists in K8s
Conjur->App: Return Conjur access token
rafis3 commented 4 years ago

@izgeri this looks good! I would add a little bit more details that I think are relevant for someone that learns about this. Let me know what you think.

object App K8s Conjur
App->App: Generate CSR
App->Conjur: Inject client certificate request (with CSR)
Conjur->K8s: Validate pod exists in namespace
Conjur->K8s: Validate application identity resource exists in K8s
Conjur->App: Error (if one occurred)
Conjur->Conjur: Sign certificate
Conjur->K8s: Run kube client "exec" to install the signed certificate
K8s->App: Install the signed Conjur certificate in the pod
K8s->Conjur: Error (if one occurred)
Conjur->App: Certificate injection result (either success or failure)
App->Conjur: Authenticate request (mutual TLS using signed certificate)
Conjur->K8s: Validate pod exists in namespace
Conjur->K8s: Validate application identity resources exist in K8s
Conjur->App: Return Conjur access token

The changes I made:

Outcome:

+-----+                                               +-----+                                                       +---------+             
| App |                                               | K8s |                                                       | Conjur  |             
+-----+                                               +-----+                                                       +---------+             
   |                                                     |                                                               |                  
   | Generate CSR                                        |                                                               |                  
   |-------------                                        |                                                               |                  
   |            |                                        |                                                               |                  
   |<------------                                        |                                                               |                  
   |                                                     |                                                               |                  
   | Inject client certificate request (with CSR)        |                                                               |                  
   |-------------------------------------------------------------------------------------------------------------------->|                  
   |                                                     |                                                               |                  
   |                                                     |                              Validate pod exists in namespace |                  
   |                                                     |<--------------------------------------------------------------|                  
   |                                                     |                                                               |                  
   |                                                     |          Validate application identity resource exists in K8s |                  
   |                                                     |<--------------------------------------------------------------|                  
   |                                                     |                                                               |                  
   |                                                     |                                       Error (if one occurred) |                  
   |<--------------------------------------------------------------------------------------------------------------------|                  
   |                                                     |                                                               |                  
   |                                                     |                                                               | Sign certificate 
   |                                                     |                                                               |----------------- 
   |                                                     |                                                               |                | 
   |                                                     |                                                               |<---------------- 
   |                                                     |                                                               |                  
   |                                                     |      Run kube client "exec" to install the signed certificate |                  
   |                                                     |<--------------------------------------------------------------|                  
   |                                                     |                                                               |                  
   |    Install the signed Conjur certificate in the pod |                                                               |                  
   |<----------------------------------------------------|                                                               |                  
   |                                                     |                                                               |                  
   |                                                     | Error (if one occurred)                                       |                  
   |                                                     |-------------------------------------------------------------->|                  
   |                                                     |                                                               |                  
   |                                                     |      Certificate injection result (either success or failure) |                  
   |<--------------------------------------------------------------------------------------------------------------------|                  
   |                                                     |                                                               |                  
   | Authenticate request (mutual TLS using signed certificate)                                                          |                  
   |-------------------------------------------------------------------------------------------------------------------->|                  
   |                                                     |                                                               |                  
   |                                                     |                              Validate pod exists in namespace |                  
   |                                                     |<--------------------------------------------------------------|                  
   |                                                     |                                                               |                  
   |                                                     |          Validate application identity resources exist in K8s |                  
   |                                                     |<--------------------------------------------------------------|                  
   |                                                     |                                                               |                  
   |                                                     |                                    Return Conjur access token |                  
   |<--------------------------------------------------------------------------------------------------------------------|                  
   |                                                     |                                                               |
orenbm commented 4 years ago

Thanks @izgeri for getting this. I actually didn't know about this tool and it's a cool one.

I won't merge my suggestions with Rafi's so it is easier to understand the diff from the original.

I have this diagram:

+-----+                                               +-----+                                                                     +---------+                                                                                            
| App |                                               | K8s |                                                                     | Conjur  |                                                                                            
+-----+                                               +-----+                                                                     +---------+                                                                                            
   |                                                     |                                                                             |                                                                                                 
   | Inject client certificate request (including Conjur host ID)                                                                      |                                                                                                 
   |---------------------------------------------------------------------------------------------------------------------------------->|                                                                                                 
   |                                                     |                                                                             |                                                                                                 
   |                                                     |                                                                             | Validate K8s Authenticator webservice exists, Conjur host exists is permitted on the webservice 
   |                                                     |                                                                             |------------------------------------------------------------------------------------------------ 
   |                                                     |                                                                             |                                                                                               | 
   |                                                     |                                                                             |<----------------------------------------------------------------------------------------------- 
   |                                                     |                                                                             |                                                                                                 
   |                                                     |                                            Validate pod exists in namespace |                                                                                                 
   |                                                     |<----------------------------------------------------------------------------|                                                                                                 
   |                                                     |                                                                             |                                                                                                 
   |                                                     |      Validate Conjur host can authenticate from the requesting K8s resource |                                                                                                 
   |                                                     |<----------------------------------------------------------------------------|                                                                                                 
   |                                                     |                                                                             |                                                                                                 
   |                                                     |                                                     Error (if one occurred) |                                                                                                 
   |<----------------------------------------------------------------------------------------------------------------------------------|                                                                                                 
   |                                                     |                                                                             |                                                                                                 
   |                                                     |                        Run "kubectl exec" to install the signed certificate |                                                                                                 
   |                                                     |<----------------------------------------------------------------------------|                                                                                                 
   |                                                     |                                                                             |                                                                                                 
   |    Install the signed Conjur certificate in the pod |                                                                             |                                                                                                 
   |<----------------------------------------------------|                                                                             |                                                                                                 
   |                                                     |                                                                             |                                                                                                 
   |                                                     | Error (if one occurred)                                                     |                                                                                                 
   |                                                     |---------------------------------------------------------------------------->|                                                                                                 
   |                                                     |                                                                             |                                                                                                 
   | Authenticate request (including Conjur host ID and the Conjur certificate)                                                        |                                                                                                 
   |---------------------------------------------------------------------------------------------------------------------------------->|                                                                                                 
   |                                                     |                                                                             |                                                                                                 
   |                                                     |                                                                             | Validate K8s Authenticator webservice exists, Conjur host exists is permitted on the webservice 
   |                                                     |                                                                             |------------------------------------------------------------------------------------------------ 
   |                                                     |                                                                             |                                                                                               | 
   |                                                     |                                                                             |<----------------------------------------------------------------------------------------------- 
   |                                                     |                                                                             |                                                                                                 
   |                                                     |                                            Validate pod exists in namespace |                                                                                                 
   |                                                     |<----------------------------------------------------------------------------|                                                                                                 
   |                                                     |                                                                             |                                                                                                 
   |                                                     |      Validate Conjur host can authenticate from the requesting K8s resource |                                                                                                 
   |                                                     |<----------------------------------------------------------------------------|                                                                                                 
   |                                                     |                                                                             |                                                                                                 
   |                                                     |                                                  Return Conjur access token |                                                                                                 
   |<----------------------------------------------------------------------------------------------------------------------------------|                                                                                                 
   |                                                     |                                                                             |                                                                                                 

I used these steps:

object App K8s Conjur
App->Conjur: Inject client certificate request (including Conjur host ID)
Conjur->Conjur: Validate K8s Authenticator webservice exists, Conjur host exists is permitted on the webservice
Conjur->K8s: Validate pod exists in namespace
Conjur->K8s: Validate Conjur host can authenticate from the requesting K8s resource
Conjur->App: Error (if one occurred)
Conjur->K8s: Run "kubectl exec" to install the signed certificate
K8s->App: Install the signed Conjur certificate in the pod
K8s->Conjur: Error (if one occurred)
App->Conjur: Authenticate request (including Conjur host ID and the Conjur certificate)
Conjur->Conjur: Validate K8s Authenticator webservice exists, Conjur host exists is permitted on the webservice
Conjur->K8s: Validate pod exists in namespace
Conjur->K8s: Validate Conjur host can authenticate from the requesting K8s resource
Conjur->App: Return Conjur access token

What i added:

orenbm commented 4 years ago

btw, i would add this diagram also to the K8s authenticator client. what do you think?

rafis3 commented 4 years ago

That's a great idea @orenbm but I suggest keeping one source of truth, so I'd recommend that the authn client would have a link pointing to this diagram located under Conjur.

izgeri commented 4 years ago

@rafis3 @orenbm - if I look at your two proposals and try to justify them, here is what I come up with. let me know what you think. if it looks good I'll put up a PR to add it (and a link in the authn-k8s client, too)

sequence definition:

object App K8s Conjur
App->App: Generate certificate signing request (CSR)
App->Conjur: Send inject client certificate request (including Conjur host ID)
Conjur->Conjur: Validate K8s Authenticator webservice exists, Conjur host exists, Conjur host is permitted on the webservice
Conjur->K8s: Validate pod exists in namespace
Conjur->K8s: Validate application identity resource exists in K8s
Conjur->App: Error (if one occurred)
Conjur->Conjur: Sign certificate
Conjur->K8s: Run kube client "exec" to install the signed certificate
K8s->App: Install the signed Conjur certificate in the pod
K8s->Conjur: Error (if one occurred)
App->Conjur: Authenticate request (including Conjur host ID, mutual TLS using signed certificate)
Conjur->Conjur: Validate K8s Authenticator webservice exists, Conjur host exists, Conjur host is permitted on the webservice
Conjur->K8s: Validate pod exists in namespace
Conjur->K8s: Validate application identity resource exists in K8s
Conjur->App: Return Conjur access token

Questions

@rafis3 you had replaced

Conjur->K8s: Validate application identity resource exists in K8s

with

Conjur->K8s: Validate Conjur host can authenticate from the requesting K8s resource

But I think the former is clearer, and more in line with what it's actually doing based on my review of the code. But maybe you understand it differently - can you clarify why you made this change?

@orenbm you had added

Conjur->App: Certificate injection result (either success or failure)

after the certificate injection, but I don't think this is accurate. I think this is captured by the line a few steps above which says:

Conjur->App: Error (if one occurred)

Conjur sends the error back to the app if it's unable to validate the request, then proceeds asynchronously with the certificate injection. It logs an error if the cert injection fails, but I don't think it sends any further info to the app. The app can inspect and determine that the certificate has not arrived, and kick off another login attempt if desired. Does this make sense?

orenbm commented 4 years ago

@izgeri you switched between our suggestions, @rafis3 please note.

I made this change (application identity) because we don't verify that an application identity resource exists in K8s. I don;t blame you from thinking that, and I am in the middle of a refactor to the application identity area because it is not clear (i learned that recently).

I changed the class name from ApplicationIdentity to ResourceRestrictions and wrote the following comment above the class definition:

    # This class represents the restrictions that are set on a Conjur host regarding
    # the K8s resources that it can authenticate with Conjur from.
    # It consists a list of K8sResource objects which represent the resource
    # restriction that need to be met in an authentication request.
    #
    # For example, if `resources` includes the K8sResource:
    #   - type: "namespace"
    #   - value: "some-namespace"
    #
    # then this Conjur host can authenticate with Conjur only from a pod that is
    # part of the namespace "some-namespace"

The restrictions are set either in the host id or in the host annotations. Is it clearer now what we do in this step? Or maybe you understood it also before?

How would you phrase the line in the diagram knowing the above?

rafis3 commented 4 years ago

@izgeri regarding my comments:

Conjur->K8s: Validate Conjur host can authenticate from the requesting K8s resource

I meant to say that the caller pod is checked based on the app restrictions, as @orenbm described. We can change the wording. But I was also wrong, should have looked again in the code before writing it. This part is done in the authenticate step, not in the client cert injection.

Conjur->App: Certificate injection result (either success or failure)

The authn client communicates with the Conjur REST API, while the certificate should be found asynchronously on the filesystem, the REST API returns a result so that the code can continue.

orenbm commented 4 years ago

This part is done in the authenticate step, not in the client cert injection.

it happens in both steps.

rafis3 commented 4 years ago

@orenbm yeah now I see it, thanks for pointing that out, I missed it in validate. I think it's redundant, we don't need to check the correlation between the host expected attributes and the actual in both APIs. The reason for injecting a certificate is to provide an identity to the calling pod, but validating the identity should be done in authenticate. Makes sense?

orenbm commented 4 years ago

So why even send a host id in the inject cert request? As long as we send a host id i think we need to verify it.

izgeri commented 4 years ago

@orenbm I want to wrap this up, and I think my last iteration is almost good enough, except for your one comment about "application identity".

I think we are both saying the same thing, and neither line is quite clear enough.

my line:

Conjur->K8s: Validate application identity resource exists in K8s

your line:

Conjur->K8s: Validate Conjur host can authenticate from the requesting K8s resource

proposed alternative:

Conjur->K8s: Validate requesting K8s resource actually exists in K8s

The crux of it is that the request comes with an application identity that lists a certain k8s resource type / name. We are checking that the given k8s resource type / name actually exists in the cluster. Does this proposed alternative make it clearer? Do you have a counter proposal?

orenbm commented 4 years ago

the thing is that your line Validate requesting K8s resource actually exists in K8s is not what happens. we don't just verify that the requesting K8s resource (extracted from the request) exists but that the requesting Conjur host can authenticate from the requesting k8s resource.

For example, we have a Conjur host that is defined as follows:

- !host
  id: some-app
  annotations:
    authn-k8s/namespace: some-namespace

and we get an authentication request with the spiffe-id spiffe://cluster.local/namespace/some-other-namespace/podname/some-pod and the Conjur host-id some-app.

In this case the requesting K8s resource is the pod some-pod that is in the namespace some-other-namespace. It actually exists in k8s but the application identity validation will fail. It will fail because the requesting Conjur host (some-app) can authenticate with Conjur only from the namespace some-namespace. So although the requesting k8s resource actually exist in k8s, the conjur host is not allowed to authenticate from it (similar to CIDR restrictions with the restricted_to field). That's why i think that Validate Conjur host can authenticate from the requesting K8s resource is more accurate.

btw, i'm in progress of changing ApplicationIdentity to ResourceRestrictions which i think will be more understandable.

izgeri commented 4 years ago

ok - so if I write the flow as:

object App K8s Conjur
App->App: Generate certificate signing request (CSR)
App->Conjur: Send inject client certificate request (including Conjur host ID)
Conjur->Conjur: Validate K8s Authenticator webservice exists, Conjur host exists, Conjur host is permitted on the webservice
Conjur->K8s: Validate pod exists in namespace
Conjur->K8s: Validate Conjur host can authenticate from the requesting K8s resource
Conjur->App: Error (if one occurred)
Conjur->Conjur: Sign certificate
Conjur->K8s: Run kube client "exec" to install the signed certificate
K8s->App: Install the signed Conjur certificate in the pod
K8s->Conjur: Error (if one occurred)
App->Conjur: Authenticate request (including Conjur host ID, mutual TLS using signed certificate)
Conjur->Conjur: Validate K8s Authenticator webservice exists, Conjur host exists, Conjur host is permitted on the webservice
Conjur->K8s: Validate pod exists in namespace
Conjur->K8s: Validate Conjur host can authenticate from the requesting K8s resource
Conjur->App: Return Conjur access token

does this look good? can I put up some PRs to add this to our code? @rafis3 @orenbm

orenbm commented 4 years ago

this is actually my bad but i think that having this text Validate Conjur host can authenticate from the requesting K8s resource with a line from Conjur to K8s is a bit weird. Maybe let's change it to Validate the requesting K8s resource applies to the Conjur host's authentication restrictions.

I am ok with whichever decision you take if you think it's ok.

other than that, i am ok for a PR. thanks!

izgeri commented 4 years ago

does it help to know that I meant this line to refer to this check? https://github.com/cyberark/conjur/blob/807d5d912694d848e734ea1b4e732f85dcfae9be/app/domain/authentication/authn_k8s/validate_application_identity.rb#L106

which uses the k8s API to verify that a resource of the given type and name exists in the given namespace?

rafis3 commented 4 years ago

Regarding the amendment @orenbm suggested. I think both options sound good and clear.

Regarding this sentence: Validate K8s Authenticator webservice exists, Conjur host exists, Conjur host is permitted on the webservice I think it should be permitted to instead of on.

Other than these small comments, all looks good to me.

izgeri commented 4 years ago

@orenbm don't we have a flow diagram for authn-k8s in this repo now? can you please add a link to the file here so we can close the issue?

it might be nice to make sure flow diagrams are linked from CONTRIBUTING too - they're super handy for new devs to understand the project.

orenbm commented 4 years ago

thanks @izgeri , the diagram can be found here. care to add the links in the places you think they should go to?

izgeri commented 4 years ago

I think it should go in CONTRIBUTING.md, so that contributors can find that reference if they're going to work on authn-k8s.

I think you could make a case for updating this project's style guide, too, now that we have the style guide for Ruby in the community repo - I will leave both for the people actually doing the development work on this project :)