OpenUnison / openunison-k8s

Access portal for Kubernetes
Apache License 2.0
105 stars 5 forks source link

Audience URI and SSO URL in okta for SAML2 #71

Closed eyupdzhanY1 closed 1 year ago

eyupdzhanY1 commented 1 year ago

image

If set to base https://k8sou.HOST.com/ it keeps redirected to login splash , what is the correct values ?

Looping networking tab from chrome. image

eyupdzhanY1 commented 1 year ago

If there is an example SAML configuration in okta would help this issue i believe. image

mlbiam commented 1 year ago

You can grab your metadata from https://k8sou.domain.com/auth/forms/saml2_rp_metadata.jsp (assuming you've gotten openunison deployed?). Curious, why use SAML2 with Okta instead of OIDC?

eyupdzhanY1 commented 1 year ago

Not in our product plan with okta, oidc requires extra fees as i get to learn.

mlbiam commented 1 year ago

@eyupdzhanY1 were you able to upload the saml2 metadata?

eyupdzhanY1 commented 1 year ago

Upload it where exactly ? @mlbiam I can access it through mentioned link.

mlbiam commented 1 year ago

ugh. didn't realize okta wouldn't let you just run let you upload your metadata. i'll test it out and get you specific instructions.

mlbiam commented 1 year ago

this should get you what you need.

Screenshot 2023-03-24 at 1 55 00 PM

eyupdzhanY1 commented 1 year ago

Thank a lot! Will try this on monday and post an update.

eyupdzhanY1 commented 1 year ago

Login is successful but I am unable to access dashboard, and in the attributes page there is only user name with email exist. user1@domain.com, in the user CRD there is my user generated but instead of "1" in the user name we have "x-49-x" and instead of @ there is "x-64-x". How can I assign this user role in the ClusterRoleBinding User spec looks like this. And groups are really empty, does it mean no information passed to openunison from okta?

spec:
  email: ''
  first_name: ''
  groups: []
  last_name: ''
  sub: user1@domain.com
  uid: userx-49-xx-64-xdomain.com

I tried these access user names. None gave me access to dashboard.

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: cluster-admins
subjects:
  - kind: User
    name: https://k8sou.domain.com/auth/idp/k8sIdp#userx-49-xx-64-xdomain.com
  - kind: User
    name: user1@domain.com
  - kind: User
    name: userx-49-xx-64-xdomain.com

roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
mlbiam commented 1 year ago

Login is successful but I am unable to access dashboard,

Can you provide some details? What do you see on the screen?

only user name with email exist.

Your username is whatever you specified in the Application username section of your SAML2 Okta configuraiton. By default it's your Okta username. Looking at your User object I see user1@domain.com. Is this not what you were expecting?

he user CRD there is my user generated but instead of "1" in the user name we have "x-49-x" and instead of @ there is "x-64-x"

This is only used internally by OpenUnison. The x-49-x is used to make sure that any username can be translated into a kubernetes name with its DNS restrictions. It can be ignored. The important field is sub

I tried these access user names. None gave me access to dashboard.

this should work:

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: cluster-admins
subjects:
  - kind: User
    name: user1@domain.com
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

That said, you're using AKS, right? Did you enable impersonation in your values.yaml? (enable_impersonation: true)

mlbiam commented 1 year ago

Login is successful but I am unable to access dashboard,

Can you provide some details? What do you see on the screen?

only user name with email exist.

Your username is whatever you specified in the Application username section of your SAML2 Okta configuraiton. By default it's your Okta username. Looking at your User object I see user1@domain.com. Is this not what you were expecting?

he user CRD there is my user generated but instead of "1" in the user name we have "x-49-x" and instead of @ there is "x-64-x"

This is only used internally by OpenUnison. The x-49-x is used to make sure that any username can be translated into a kubernetes name with its DNS restrictions. It can be ignored. The important field is sub

I tried these access user names. None gave me access to dashboard.

this should work:

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: cluster-admins
subjects:
  - kind: User
    name: user1@domain.com
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

That said, you're using AKS, right? Did you enable impersonation in your values.yaml? (enable_impersonation: true)

eyupdzhanY1 commented 1 year ago

@mlbiam I am using AKS, and impersonation was set to false. Enabled it now. image

image

This is how binding was done.

subjects:
  - kind: User
    name: "https://k8sou.com/auth/idp/k8sIdp#user1@domain.com"
mlbiam commented 1 year ago

Odd, same thing we saw in https://github.com/OpenUnison/openunison-k8s/issues/70#issuecomment-1478330257. Try following the same steps?

mlbiam commented 1 year ago

Right, delete the ou-tls-certificate Secret and redeploy. That will force the operator to create a new secret with the correct host name for your API proxy

eyupdzhanY1 commented 1 year ago

@mlbiam The secret does not exist but network.createIngressCertificate is false.

mlbiam commented 1 year ago

Oh, then how are you generating the certificate?

eyupdzhanY1 commented 1 year ago

I am not, it all sits behind nginx, and there is load balancer IP.

mlbiam commented 1 year ago

so it's a wildcard certificate? is your network.api_server_host set to a DNS entry that points to that NGINX? Please post your values.yaml

eyupdzhanY1 commented 1 year ago

Wildcard domains all point there *.test.domain.com , and ingress entries forward to service in openunison correct me if i am wrong.

network:
  openunison_host: "k8sou.test.domain.com"
  dashboard_host: "k8sdb.test.domain.com"
  api_server_host: "k8sapi.test.domain.com"
  session_inactivity_timeout_seconds: 900
  k8s_url: https://hcp.eastus2.azmk8s.io:443
  force_redirect_to_tls: true
  createIngressCertificate: false
  ingress_type: nginx
  ingress_annotations: {}

cert_template:
  ou: "Kubernetes"
  o: "domain"
  l: "Production Cluster"
  st: "East US 2"
  c: "USA"

image: docker.io/tremolosecurity/openunison-k8s
myvd_config_path: "WEB-INF/myvd.conf"
k8s_cluster_name: openunison-cp
enable_impersonation: true

impersonation:
  use_jetstack: true
  jetstack_oidc_proxy_image: docker.io/tremolosecurity/kube-oidc-proxy:latest
  explicit_certificate_trust: true

dashboard:
  namespace: "kubernetes-dashboard"
  cert_name: "kubernetes-dashboard-certs"
  label: "k8s-app=kubernetes-dashboard"
  service_name: kubernetes-dashboard
  require_session: true

certs:
  use_k8s_cm: false

trusted_certs:
  - name: okta-cert
    pem_b64: Certificate in base64

monitoring:
  prometheus_service_account: system:serviceaccount:monitoring:prometheus-k8s

saml:
  idp_url: "https://domain.okta.com/app/STRING/sso/saml/metadata"

network_policies:
  enabled: false
  ingress:
    enabled: true
    labels:
      app.kubernetes.io/name: ingress-nginx
  monitoring:
    enabled: true
    labels:
      app.kubernetes.io/name: monitoring
  apiserver:
    enabled: false
    labels:
      app.kubernetes.io/name: kube-system

services:
  enable_tokenrequest: false
  token_request_audience: api
  token_request_expiration_seconds: 600
  node_selectors: []

openunison:
  replicas: 1
  non_secret_data:
    K8S_DB_SSO: saml2
    PROMETHEUS_SERVICE_ACCOUNT: system:serviceaccount:monitoring:prometheus-k8s
    SHOW_PORTAL_ORGS: "false"
  secrets: []
  html:
    image: docker.io/tremolosecurity/openunison-k8s-html
  enable_provisioning: false
  use_standard_jit_workflow: true
mlbiam commented 1 year ago

Is the ingress signed by a commercial CA? or is it an internal CA? Is this CA distributed to your workstation where you're running kubectl from?

eyupdzhanY1 commented 1 year ago

It is signed by commercial CA, it works fine as long as you are within the company network, had no issues with TLS so far.

mlbiam commented 1 year ago

run kubectl get nodes --v=11. Should give some details as to why the cert isn't being accepted by kubectl.

eyupdzhanY1 commented 1 year ago

Adding wildcard certificate as ou-tls-certificate secret first, then deploying worked for connection.

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: k8sou-admins
subjects:
  - kind: User
    name: "user@domain.com"
 roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

Worked for me , user is whatever "sub" is under openunison.tremolo.io CRD's user resource.

eyupdzhanY1 commented 1 year ago

@mlbiam Thank you again for all the help, reading groups are still a trouble, both saml2 and oidc setup does not work. For oidc we use AzureAD but delegation and scoping seems to be in the way of things.

And okta does not reply with any memberOf fields for saml2.

mlbiam commented 1 year ago

For oidc we use AzureAD but delegation and scoping seems to be in the way of things.

Your groups are in azuread? Do you sync these groups into Okta?

eyupdzhanY1 commented 1 year ago

We do sync , not everything but most groups. I am trying to figure out why saml2 groups appear empty in user CRD.

mlbiam commented 1 year ago

We do sync , not everything but most groups

in your Okta SAML configuration, what do you have for your Group Attribute Statement? See attached screenshot from my okta deployment: Screenshot 2023-03-27 at 10 29 10 AM

eyupdzhanY1 commented 1 year ago

@mlbiam Yes this was able to get groups that are synced thank you , but still not full AzureAD. Do you know if openunison can only work with delegated user in the azuread setup ? Apps are super limited in our current structure.

mlbiam commented 1 year ago

but still not full AzureAD.

So just to make sure I understand correctly. Not all groups are synced from AzureAD to Okta, but you need groups that haven't been synced to Okta too?

Do you know if openunison can only work with delegated user in the azuread setup ?

OOTB we can lookup groups in AzureAD if you authenticate to AzureAD. It'll take some YAML, but if you can get a client secret that can lookup users in your AzureAD openunison could lookup groups from azuread based on the loggedin user's upn/email.

eyupdzhanY1 commented 1 year ago

If it is delegated permissions i can get read on anything, when it switches to app permissions have to scope and it can not read groups. About saml2 , we got as far as we can , it works and no more info possible from it. AzureAD seems better option if can read groups somehow.

Type: A = Application Permission, D = Delegate Permission

 

Ver Type Method
V1 A,D GET /groups
V1 A,D GET /groups/{group-id}/permissionGrants
V1 A,D GET /groups/{id}
V1 A,D GET /groups/{id}/memberOf
V1 A,D GET /groups/{id}/members
V1 A,D GET /groups/{id}/owners
V1 D GET /groups/{id}/transitiveMemberOf
V1 A,D GET /groups/{id}/transitiveMembers
V1 A,D GET /groups/delta
V1 D GET /me/memberOf
V1 A,D GET /me/transitiveMemberOf
V1 D GET /users/{id | userPrincipalName}/memberOf
V1 A,D GET /users/{id | userPrincipalName}/transitiveMemberOf
V1 A,D POST /directoryObjects/{id}/checkMemberGroups
V1 A,D POST /directoryObjects/{id}/checkMemberObjects
V1 A,D POST /directoryObjects/{id}/getMemberGroups
V1 A,D POST /directoryObjects/{id}/getMemberObjects

Type: A = Application Permission, D = Delegate Permission

 

Ver Type Method V1 A,D GET /groups V1 A,D GET /groups/{group-id}/permissionGrants V1 A,D GET /groups/{id} V1 A,D GET /groups/{id}/memberOf V1 A,D GET /groups/{id}/members V1 A,D GET /groups/{id}/owners V1 D GET /groups/{id}/transitiveMemberOf V1 A,D GET /groups/{id}/transitiveMembers V1 A,D GET /groups/delta V1 D GET /me/memberOf V1 A,D GET /me/transitiveMemberOf V1 D GET /users/{id | userPrincipalName}/memberOf V1 A,D GET /users/{id | userPrincipalName}/transitiveMemberOf V1 A,D POST /directoryObjects/{id}/checkMemberGroups V1 A,D POST /directoryObjects/{id}/checkMemberObjects V1 A,D POST /directoryObjects/{id}/getMemberGroups V1 A,D POST /directoryObjects/{id}/getMemberObjects

mlbiam commented 1 year ago

We can only do delegated if you're authenticating you to azuread. We can integrate with AzureAD directly if that is easier - https://openunison.github.io/identity%20providers/azuread/ ?

eyupdzhanY1 commented 1 year ago

Yes that is what i used to deploy with azuread. Am i missing something there ?

mlbiam commented 1 year ago

Sorry, I'm very confused. I thought you were using Okta for authentication?

eyupdzhanY1 commented 1 year ago

I am sorry for jumping around on the subject. I have 2 values yaml, 1 is for azuread, 1 is for okta saml. Okta saml is a no go because limited amount of groups we can read.

AzureAD has problems reading user groups because of scoping required for app registrations. If used delegated permissions thus using the power's of logged in user, we can read the group.

eyupdzhanY1 commented 1 year ago

When a request is made to https://graph.microsoft.com/v1.0/me/memberOf with the app registration, I can read all the groups user is part of. How does openunison request the groups ?

eyupdzhanY1 commented 1 year ago

So I dug deep and realized AppRegistration needs to be configured. manifest of app registration should look like this , changes to token version and optional claims. This allows groups info to be inside id_token.

    "accessTokenAcceptedVersion": 2,
.
.
.
    "optionalClaims": {
        "idToken": [
            {
                "name": "email",
                "source": null,
                "essential": false,
                "additionalProperties": []
            },
            {
                "name": "upn",
                "source": null,
                "essential": false,
                "additionalProperties": []
            },
            {
                "name": "family_name",
                "source": null,
                "essential": false,
                "additionalProperties": []
            },
            {
                "name": "given_name",
                "source": null,
                "essential": false,
                "additionalProperties": []
            },
            {
                "name": "preferred_username",
                "source": null,
                "essential": false,
                "additionalProperties": []
            },
            {
                "name": "groups",
                "source": "user",
                "essential": true,
                "additionalProperties": [
                    "sam_account_name"
                ]
            }
        ],
        "accessToken": [
            {
                "name": "groups",
                "source": "user",
                "essential": true,
                "additionalProperties": [
                    "sam_account_name"
                ]
            }
        ],
        "saml2Token": [
            {
                "name": "groups",
                "source": null,
                "essential": false,
                "additionalProperties": [
                    "sam_account_name"
                ]
            }
        ]
    },

Then when values.yaml should be edited to have oidc.claims.groups=groups

oidc:
  claims:
    groups: groups

In the end finally a group info can be read !

mlbiam commented 1 year ago

it looks like the samAccountName is available so you don't need the additional lookup. I take it you're working at this point and we can close out this issue?

eyupdzhanY1 commented 1 year ago

Yes closing the issue thank you, just wanted to document developments.