Files
teleport/lib/devicetrust/authz/authz.go
T
Alan Parra 8ef8324b8c Enable role-based device authz for DB, k8s and SSH (#20640)
* Expose device verification methods in lib/devicetrust/authz

* Set device fields in auth.Context.GetAccessState

* Enable role-based device verification for SSH

* Enable role-based device verification for DBs

* Add TODO for better SSH error messages

* Do not override device error on lib/kube/proxy

* Run gci
2023-01-27 21:11:01 +00:00

93 lines
3.0 KiB
Go

// Copyright 2022 Gravitational, Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package authz
import (
"sync"
"github.com/gravitational/trace"
log "github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh"
"github.com/gravitational/teleport"
"github.com/gravitational/teleport/api/constants"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/devicetrust/config"
"github.com/gravitational/teleport/lib/tlsca"
)
// IsTLSDeviceVerified returns true if ext contains all required device
// extensions.
func IsTLSDeviceVerified(ext *tlsca.DeviceExtensions) bool {
// Expect all device extensions to be present.
return ext != nil && ext.DeviceID != "" && ext.AssetTag != "" && ext.CredentialID != ""
}
// VerifyTLSUser verifies if the TLS identity has the required extensions to
// fulfill the device trust configuration.
func VerifyTLSUser(dt *types.DeviceTrust, identity tlsca.Identity) error {
return verifyDeviceExtensions(dt, identity.Username, IsTLSDeviceVerified(&identity.DeviceExtensions))
}
// IsSSHDeviceVerified returns true if cert contains all required device
// extensions.
func IsSSHDeviceVerified(cert *ssh.Certificate) bool {
// Expect all device extensions to be present.
return cert != nil &&
cert.Extensions[teleport.CertExtensionDeviceID] != "" &&
cert.Extensions[teleport.CertExtensionDeviceAssetTag] != "" &&
cert.Extensions[teleport.CertExtensionDeviceCredentialID] != ""
}
// VerifySSHUser verifies if the SSH certificate has the required extensions to
// fulfill the device trust configuration.
func VerifySSHUser(dt *types.DeviceTrust, cert *ssh.Certificate) error {
if cert == nil {
return trace.BadParameter("cert required")
}
username := cert.KeyId
return verifyDeviceExtensions(dt, username, IsSSHDeviceVerified(cert))
}
func verifyDeviceExtensions(dt *types.DeviceTrust, username string, verified bool) error {
mode := config.GetEffectiveMode(dt)
maybeLogModeMismatch(mode, dt)
switch {
case mode != constants.DeviceTrustModeRequired:
return nil // OK, extensions not enforced.
case !verified:
log.
WithField("User", username).
Debug("Device Trust: denied access for unidentified device")
return trace.AccessDenied("unauthorized device")
default:
return nil
}
}
var logModeOnce sync.Once
func maybeLogModeMismatch(effective string, dt *types.DeviceTrust) {
if dt == nil || dt.Mode == "" || effective == dt.Mode {
return
}
logModeOnce.Do(func() {
log.Warnf("Device Trust: mode %q requires Teleport Enterprise. Using effective mode %q.", dt.Mode, effective)
})
}