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

[vnet] mTLS for IPC on Windows #51856

Open
wants to merge 1 commit into
base: nklaassen/windows-dns-configuration
Choose a base branch
from

Conversation

nklaassen
Copy link
Contributor

Part of RFD 195.

This PR sets up mTLS for the gRPC service provided by the VNet client application (tsh or Connect) to the Windows service.

Following the design in the RFD, the directory that the service credentials are written to is configured with Windows ACLs so that only the LocalSystem account can read the files. This way, the client can trust that any client connecting to it already has LocalSystem permissions and is probably the VNet Windows service.

@nklaassen nklaassen added no-changelog Indicates that a PR does not require a changelog entry vnet backport/branch/v17 labels Feb 5, 2025
Comment on lines +53 to +54
// longer than any individual Teleport session. Going with a month for now.
certTTL = 30 * 12 * time.Hour
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going with a month for now.

  certTTL = 30 * 12 * time.Hour

This is 15d, no? Also a minor nit, but I would say "30 days" or "15 days" instead of "a month" - a month is not an easily defined measure of time.

Comment on lines +40 to +41
trustedCAPEM []byte
certPEM []byte
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Document what is inside the PEM.

Suggested change
trustedCAPEM []byte
certPEM []byte
trustedCAPEM []byte // X.509 CA certificate
certPEM []byte // X.509 certificate for the vnet proccess

// there's no way to fetch the cluster signature_algorithm_suite or unify
// suites across multiple root clusters, so just statically use ECDSA
// P-256 for these keys.
keyAlgo = cryptosuites.ECDSAP256
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, would we ever have to customize these? These are only for IPC/local vnet connections, right?

Comment on lines +57 to +72
serverCAKey, err := cryptosuites.GenerateKeyWithAlgorithm(keyAlgo)
if err != nil {
return nil, trace.Wrap(err, "generating key")
}
clientCAKey, err := cryptosuites.GenerateKeyWithAlgorithm(keyAlgo)
if err != nil {
return nil, trace.Wrap(err, "generating key")
}
serverSigner, err := cryptosuites.GenerateKeyWithAlgorithm(keyAlgo)
if err != nil {
return nil, trace.Wrap(err, "generating key")
}
clientSigner, err := cryptosuites.GenerateKeyWithAlgorithm(keyAlgo)
if err != nil {
return nil, trace.Wrap(err, "generating key")
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Add a little more detail?

Suggested change
serverCAKey, err := cryptosuites.GenerateKeyWithAlgorithm(keyAlgo)
if err != nil {
return nil, trace.Wrap(err, "generating key")
}
clientCAKey, err := cryptosuites.GenerateKeyWithAlgorithm(keyAlgo)
if err != nil {
return nil, trace.Wrap(err, "generating key")
}
serverSigner, err := cryptosuites.GenerateKeyWithAlgorithm(keyAlgo)
if err != nil {
return nil, trace.Wrap(err, "generating key")
}
clientSigner, err := cryptosuites.GenerateKeyWithAlgorithm(keyAlgo)
if err != nil {
return nil, trace.Wrap(err, "generating key")
}
serverCAKey, err := cryptosuites.GenerateKeyWithAlgorithm(keyAlgo)
if err != nil {
return nil, trace.Wrap(err, "generating server CA key")
}
clientCAKey, err := cryptosuites.GenerateKeyWithAlgorithm(keyAlgo)
if err != nil {
return nil, trace.Wrap(err, "generating client CA key")
}
serverSigner, err := cryptosuites.GenerateKeyWithAlgorithm(keyAlgo)
if err != nil {
return nil, trace.Wrap(err, "generating server key")
}
clientSigner, err := cryptosuites.GenerateKeyWithAlgorithm(keyAlgo)
if err != nil {
return nil, trace.Wrap(err, "generating client key")
}


serverCAPEM, err := tlsca.GenerateSelfSignedCAWithSigner(serverCAKey, pkix.Name{CommonName: "TeleportVNet Server CA"}, nil /*dnsNames*/, certTTL)
if err != nil {
return nil, trace.Wrap(err, "generating self-signed CA")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return nil, trace.Wrap(err, "generating self-signed CA")
return nil, trace.Wrap(err, "generating self-signed server CA")

// O: Set Owner as current user (Windows won't allow LocalSystem to be the owner)
// G: Set Primary Group as current user
// D: Discretionary ACL
// Grant GA (Generic All) to LocalSystam
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Grant GA (Generic All) to LocalSystam
// Grant GA (Generic All) to LocalSystem

// Grant GA (Generic All) to LocalSystam
// Grant GW (Generic Write) to the current user so we can add files
// Deny GR (Generic Read) for the current user so other processes can't read the credentials
// OICI (Object Inherit, Container Inherit) propagates permissions to files/folders
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I appreciate the comment block above, this would be extremely opaque without it!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL a _windows_test.go file will still auto-apply the windows build tag, I thought the file had to end with the build tag. This is nice.

require.NoError(t, creds.client.write(credPath))

_, err = readCredentials(credPath)
require.Error(t, err, "expected no access to creds")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we check for a particular error type? What do we get, fs.ErrPermission?

for _, f := range files {
fp := filepath.Join(credPath, f)
_, err := os.ReadFile(fp)
require.Error(t, err, "expected no access to %s", fp)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for checking for a specific error. Also, Keep Going.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport/branch/v17 no-changelog Indicates that a PR does not require a changelog entry size/md vnet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants