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

Suggestion for Auth interface #16

Open
rorycl opened this issue Jun 14, 2020 · 2 comments
Open

Suggestion for Auth interface #16

rorycl opened this issue Jun 14, 2020 · 2 comments

Comments

@rorycl
Copy link

rorycl commented Jun 14, 2020

Hi

It would be cool to consider different auth providers for the project. The yaml file might be one provider and the openid one you have added is another. Obvious extensions would be LDAP and other database providers.

Despite our UserPrincipals definitions now differing (between sshtokenca and sshagentca), I was thinking of something along the following lines:

type UserPrincipals struct {                                              
    Name        string                                                    
    Principals  []string                                                  
    PublicKey   ssh.PublicKey                                             
    /// Hosts   []hosts       // for possible host certs?                 
    Fingerprint string
    OTP         string                                                    
    Expiry      Time.Time                                                 
}                                                                         

type Auth interface {                                                     

    // extract a user by fingerprint, also checking expiry
    UserByFingerprint(string) (*UserPrincipals, error)

    // extract a user by publickey, also checking expiry                  
    UserByPubKey(*ssh.Publickey) (*UserPrincipals, error)                 
    
    // check if otp is supported
    HasOTP() bool              
    
    // validate otp if provided
    OTPValidate(*UserPrincipals, string) (bool, error)                    
                                                                          
    // show the auth type, to allow for logging of mixed auth types       
    AuthType() string
}

The user map could hang off a server struct which holds both the CA server configuration and SSH server stuff, so held in one place.

Server configuration would be done with a separate .cfg file and then auth could be provided by various auth backends, eg auth/authyaml, auth/authoidc and so on.

@candlerb
Copy link
Owner

When you say "auth provider", I think this means two different things:

  • an authentication provider (like openidc or ssh pubkey), by which a user can prove their identity
  • an authorization provider (like the YAML file or LDAP) which says that a given user is eligible for a certificate, and if so, what principals to include

I did wonder about supporting multiple oidc authentication providers. However that's more easily implemented by using Dex as middleware - and Dex's web UI will let you choose provider more cleanly than a keyboard-interactive challenge asking you to select between providers.

Factoring out authorization so that you can use LDAP is a nice feature for those sites which already use LDAP. It could also have an sql or etcd backend (like Dex) plus an API for managing the data in the backend (like Dex). If you continue down this path, it becomes easier to integrate ssh certificate issuance directly into Dex - or at least, modify Dex so that it can return custom claims for the SSH cert principals. I made a hack to Dex so it can return group claims here, it could be rewritten to arbitrary claims - or you could use groups like ssh:foo to get foo as a principal in your certificate.

I did initially want to support Yubikey OTP for 2FA. OpenSSH allows you to do combined authentication, where you must pass publickey and keyboard-interactive to be allowed to login.

Unfortunately, the Go ssh server doesn't allow this - it has a hard-coded policy that one successful authentication is sufficient. I don't want to reimplement bits of the core of x/crypto/ssh, especially as there are a lot of package-local variables.

I don't think that an OTP by itself is sufficient proof of identity, unless the OTP generator has hardware PIN and lockout. Otherwise, anyone who picks up the token can use it.

An OpenSSH ecsda-sk key, protected by a FIDO/U2F key, is strong: you need the private key file and the passphrase to the private key file and the correct U2F key. sshagentca already works with this, with no changes - the only requirement is that your client is OpenSSH 8.2+ to support ecdsa-sk.

So in summary:

  • additional authentication providers could easily be added, but I don't see any useful ones other than pubkey and openidc
  • pluggable authorization providers (to replace YAML) would be more useful, but not something I need myself

There is one thing though: I would like to move the user definitions out of the main server config into a separate YAML file. This would allow me to grant rights to someone to be able to modify who certificates are issued to, without being able to modify the overall server configuration (such as the maximum certificate lifetime) and without needing a server restart when the user authorization file changes.

@rorycl
Copy link
Author

rorycl commented Jun 16, 2020

Hi. All your points make sense.

The OTP I'm suggesting would be an additional authentication step to publickey authentication. That wouldn't be necessary perhaps with the recent support for Yubikey OTP support, but we don't use those devices.

I very much agree with separating the server configuration from the user definitions. I suggest the code for latter moves to an auth section of the project with a default yaml provider.

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

No branches or pull requests

2 participants