mirror of https://github.com/minio/minio.git
Support user certificate based authentication on SFTP (#19650)
This commit is contained in:
parent
6a15580817
commit
b413ff9fdb
|
@ -18,6 +18,7 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
|
@ -162,6 +163,7 @@ func startSFTPServer(args []string) {
|
|||
port int
|
||||
publicIP string
|
||||
sshPrivateKey string
|
||||
userCaKeyFile string
|
||||
)
|
||||
allowPubKeys := supportedPubKeyAuthAlgos
|
||||
allowKexAlgos := preferredKexAlgos
|
||||
|
@ -197,6 +199,8 @@ func startSFTPServer(args []string) {
|
|||
allowCiphers = filterAlgos(arg, strings.Split(tokens[1], ","), supportedCiphers)
|
||||
case "mac-algos":
|
||||
allowMACs = filterAlgos(arg, strings.Split(tokens[1], ","), supportedMACs)
|
||||
case "trusted-user-ca-key":
|
||||
userCaKeyFile = tokens[1]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -278,6 +282,56 @@ func startSFTPServer(args []string) {
|
|||
},
|
||||
}
|
||||
|
||||
if userCaKeyFile != "" {
|
||||
keyBytes, err := os.ReadFile(userCaKeyFile)
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Errorf("invalid arguments passed, trusted user certificate authority public key file is not accessible: %v", err), "unable to start SFTP server")
|
||||
}
|
||||
|
||||
caPublicKey, _, _, _, err := ssh.ParseAuthorizedKey(keyBytes)
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Errorf("invalid arguments passed, trusted user certificate authority public key file is not parseable: %v", err), "unable to start SFTP server")
|
||||
}
|
||||
|
||||
sshConfig.PublicKeyCallback = func(c ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
|
||||
_, ok := globalIAMSys.GetUser(context.Background(), c.User())
|
||||
if !ok {
|
||||
return nil, errNoSuchUser
|
||||
}
|
||||
|
||||
// Verify that client provided certificate, not only public key.
|
||||
cert, ok := key.(*ssh.Certificate)
|
||||
if !ok {
|
||||
return nil, errSftpPublicKeyWithoutCert
|
||||
}
|
||||
|
||||
// ssh.CheckCert called by ssh.Authenticate accepts certificates
|
||||
// with empty principles list so we block those in here.
|
||||
if len(cert.ValidPrincipals) == 0 {
|
||||
return nil, errSftpCertWithoutPrincipals
|
||||
}
|
||||
|
||||
// Verify that certificate provided by user is issued by trusted CA,
|
||||
// username in authentication request matches to identities in certificate
|
||||
// and that certificate type is correct.
|
||||
checker := ssh.CertChecker{}
|
||||
checker.IsUserAuthority = func(k ssh.PublicKey) bool {
|
||||
return bytes.Equal(k.Marshal(), caPublicKey.Marshal())
|
||||
}
|
||||
_, err = checker.Authenticate(c, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ssh.Permissions{
|
||||
CriticalOptions: map[string]string{
|
||||
"accessKey": c.User(),
|
||||
},
|
||||
Extensions: make(map[string]string),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
sshConfig.AddHostKey(private)
|
||||
|
||||
handleSFTPSession := func(channel ssh.Channel, sconn *ssh.ServerConn) {
|
||||
|
|
|
@ -119,3 +119,9 @@ var errInvalidMaxParts = errors.New("Part number is greater than the maximum all
|
|||
|
||||
// error returned for session policies > 2048
|
||||
var errSessionPolicyTooLarge = errors.New("Session policy should not exceed 2048 characters")
|
||||
|
||||
// error returned in SFTP when user used public key without certificate
|
||||
var errSftpPublicKeyWithoutCert = errors.New("public key authentication without certificate is not accepted")
|
||||
|
||||
// error returned in SFTP when user used certificate which does not contain principal(s)
|
||||
var errSftpCertWithoutPrincipals = errors.New("certificates without principal(s) are not accepted")
|
||||
|
|
|
@ -242,3 +242,16 @@ hmac-sha1
|
|||
hmac-sha1-96
|
||||
```
|
||||
|
||||
### Certificate-based authentication
|
||||
|
||||
`--sftp=trusted-user-ca-key=...` specifies a file containing public key of certificate authority that is trusted
|
||||
to sign user certificates for authentication.
|
||||
|
||||
Implementation is identical with "TrustedUserCAKeys" setting in OpenSSH server with exception that only one CA
|
||||
key can be defined.
|
||||
|
||||
If a certificate is presented for authentication and has its signing CA key is in this file, then it may be
|
||||
used for authentication for any user listed in the certificate's principals list.
|
||||
|
||||
Note that certificates that lack a list of principals will not be permitted for authentication using trusted-user-ca-key.
|
||||
For more details on certificates, see the CERTIFICATES section in ssh-keygen(1).
|
||||
|
|
Loading…
Reference in New Issue