argoproj / argo-cd

Declarative Continuous Deployment for Kubernetes
https://argo-cd.readthedocs.io
Apache License 2.0
17.46k stars 5.3k forks source link

Add support for Google Cloud Identity Access Proxy (IAP) #2224

Open ExalDraen opened 5 years ago

ExalDraen commented 5 years ago

Summary

Make it possible to host ArgoCD on GKE behind Google cloud identity access proxy (IAP).

Problem statement

Google Cloud IAP is an OAuth2 based proxy that Google cloud users can enable to secure their HTTPS resources. If enabled, it enforces an OAuth 2.0 Google Account sign-in flow that stores a token in a browser cookie for future sign-in.

Currently (ArgoCD 1.2.0-rc2), if IAP is enabled for an ArgoCD setup running on GKE, it works just fine for the Argo web UI - including OAuth2 redirection, etc.

However, access from the argocd CLI to the server is not possible to the best of my knowledge - at least not when using the --grpc-web proxy option.

I believe this is because the argocd CLI does not cope with the OAuth2 flow and thus cannot get past Google Cloud IAP.

Desired solution

A way to configure argocd to deal with the Google IAP auth flow so that the argocd CLI can be used to access ArgoCD deployments protected by Google IAP.

I do not know if it makes sense, but ideally the solution would be flexible and allow other OAuth2 flows.

Further information

Details of Google cloud access proxy can be found in the docs. Specifically, the section on programmatic access looks relevant: https://cloud.google.com/iap/docs/authentication-howto#authenticating_from_a_desktop_app

Note: This was previously mentioned on Slack where it was suggested that an issue should be created.

Contributing

I would consider contributing myself but I am not sure what design would be preferable so I think this needs to be discussed first.

jessesuen commented 5 years ago

Just wanted to say, thanks for the detailed bug description and links to all the resources.

I agree we should do something to ensure Argo CD works behind Google Cloud IAP. I think if it works for a browser, it should be solvable through CLI. I think the issue is that CLI has no concept of Google IAP's cookie and would not know to store it in local disk, let alone supply it with every CLI request.

A generic solution might be to honor any set cookie directive, and store it in a section in the ~/.argocd/config, tied to the server address. grpc-web would still need to be used, but the cookie would have to be supplied with all requests.

ExalDraen commented 5 years ago

Thanks for the feedback @jessesuen. I agree with your analysis - the CLI has no concept of the token needed to access the resource hence the requests fail.

I'm not sure what the request/response flow looks like (i.e. what headers are set at what point), but I don't think just Set-Cookie is enough - if I understand the docs correctly, the flow would have to be something like this:

  1. User configures OAuth Credential in Google console (out of band).
  2. User supplies client id + secret to (let's say) argocd login.
  3. Argo uses this to generate - and persist - a long-term refresh token
  4. Argo then uses the long-term refresh token and the client secret to generate a (1-hour) id_token

The tricky part is that most (all?) of these pieces of information need to be persisted somewhere - not sure if ~/.argocd/config is the right place.

This SO answer has some python code that sketches out how to do it, might be a useful starting point.

alexec commented 5 years ago

@jessesuen one for community contribution?

hawksight commented 4 years ago

We also use IAP and prefer to enable by default on anything private to avoid having to IP lock things. But IP locks are much easier to use with CLI tools.

I notice argocd login has a --header option, so in theory assuming someone could work out the required gcloud or series of curl commands to generate an appropriate token, would it be possible to do?:

export IAP_TOKEN="$(<insert some shell foo>)"
argocd login argocd.example.com:443 --header "'Authorization: Bearer $IAP_TOKEN"

Having had a little look through this: https://cloud.google.com/iap/docs/authentication-howto#authenticating_from_a_desktop_app

I've done similar with a service account from some python app (based on this ), but never actually as a user account.

redbaron commented 4 years ago

There is another aspect to it: ArgoCD behind IAP should get user identity from headers injected by IAP. Details can be found in https://cloud.google.com/iap/docs/identity-howto

cydergoth commented 2 years ago

I have this working using Dex AuthProxy but it's a bit of a hack. The problem I have yet to solve is how to use a GCP Service Account identity to call the ArgoCD API, either via the IAP exposed endpoint or directly backend-to-backend from StackStorm to ArgoCD API in the same cluster

    dex.config: |
        connectors:
          - type: authproxy
            id: iap_proxy
            name: "Google IAP Proxy"
            config:
              userHeader: "X-Goog-Authenticated-User-Email"
    extraArgs: # Disable HTTPS as the LBA terminates it
      - --insecure
      - --rootpath=/argocd
dpkirchner commented 2 years ago

This is promising -- do you know how to add an account to argo using a user's email address? It's not possible via the argocd-cm configmap because the account.email key will be invalid (@ isn't allowed). It looks like argo cd itself doesn't support adding accounts locally: https://github.com/argoproj/argo-cd/issues/4967

Aside: I wonder how difficult it would be to hijack argo's native support for JWTs (on the API endpoint) to understand the JWT headers Google sends.

cydergoth commented 2 years ago

In our case we don't add the accounts, it seems to work by IAP and DeX magic.

IAP also does not supply us with groups.

On Tue, May 24, 2022, 5:56 PM David Kirchner @.***> wrote:

This is promising -- do you know how to add an account to argo using a user's email address? It's not possible via the argocd-cm configmap because the account.email key will be invalid (@ isn't allowed). It looks like argo cd itself doesn't support adding accounts locally: #4967 https://github.com/argoproj/argo-cd/issues/4967

Aside: I wonder how difficult it would be to hijack argo's native support for JWTs (on the API endpoint) to understand the JWT headers Google sends.

— Reply to this email directly, view it on GitHub https://github.com/argoproj/argo-cd/issues/2224#issuecomment-1136509920, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABPWAWVTQ5DVOZ4D2X547BDVLVNBLANCNFSM4IQ6MXCA . You are receiving this because you commented.Message ID: @.***>

adrian-gierakowski commented 2 years ago

We also use IAP and prefer to enable by default on anything private to avoid having to IP lock things. But IP locks are much easier to use with CLI tools.

I notice argocd login has a --header option, so in theory assuming someone could work out the required gcloud or series of curl commands to generate an appropriate token, would it be possible to do?:

export IAP_TOKEN="$(<insert some shell foo>)"
argocd login argocd.example.com:443 --header "'Authorization: Bearer $IAP_TOKEN"

https://serverfault.com/a/1090492

probably best to use Proxy-Authorization header in case argocd cli itself uses Authorization

tsawada commented 1 year ago

has anybody got --header working with IAP? I tried

$ IAP_TOKEN=$(gcloud auth print-access-token)
$ argocd login my.server.url --header "Proxy-Authorization: Bearer ${IAP_TOKEN}" --sso

and also with --header "X-Goog-User-Project: my-project-name" but no luck

tomdurrant commented 1 year ago

Anyone managed to get this working?

SeaJaredCode commented 9 months ago

For anyone still trying to solve this, I was able to get this working -- thanks to clues on this page and the google doc linked to above.

I needed to go through the several-step process (like described in the doc) to get the code and turn that into an id_token. That id token format is not the same as the access token you get from gcloud auth print-access-token.

That process requires running a local server to accept the callback as part of the process, which means you have to add that uri to your allowed redirect links. (That part is not explicitly called out in the docs!)

The missing piece for me was the additional requirement to specify --grpc-web (though I use other grpc services via HTTP2 through iap without issue 🤷). I also had to pass in the --sso parameter. You can do this in the login command:

argocd login myargo.server.com --header "Proxy-Authorization: Bearer ${IAP_TOKEN}" --grpc-web --sso

The --grpc-web option gets stored in the argocd config after login, but the headers are not similarly captured in the configuration file/server section, so you have to pass them in with every command.

argocd app list YOUR_SERVER_HERE --header "Proxy-Authorization: Bearer ${IAP_TOKEN}"

I wrote up a way to manage getting & refreshing this token from bash in a gist that also has a wrapper to argocd that hides much of this chicanery from a developer's experience.

maroux commented 5 months ago

@SeaJaredCode fyi, you can make it headless like so:

→ export ARGO_IAP_TOKEN=$(gcloud auth print-identity-token --impersonate-service-account <some-service-account> --audiences ${CLIENT_ID} --include-email)

This assumes there's a service account and everyone who needs access has serviceAccountUser permission on that service account.

Cheers!