-
Notifications
You must be signed in to change notification settings - Fork 18k
proposal: crypto/tls: on-disk configuration #60790
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
Comments
CC @golang/security |
TLS reading from local disk seems like a non-starter. |
This proposal has been added to the active column of the proposals project |
I think one of the nice things about crypto/tls currently is that its relatively easy to reason about, in part because there is an extremely limited set of knobs that can be turned by users (for better or worse). Something like this makes that a lot more complicated. Similarly in the past we've had informal proposals about allowing programs to directly set the default TLS configuration (i.e. via a I think if we were to adopt something like this, it'd need to be strictly controlled by the person running the binary (i.e. via a GODEBUG or other env var), rather than in the source/build options. Perhaps if this is strictly focused on compliance type stuff, would it be reasonable to scope this only to FIPS mode? |
This is something that Security Information Officers want to control, regardless of certifications, as a matter of deployment policy. Being able to disable ciphers that may cause issues or are effected by a sudden vulnerability or are simply considered too weak for the specific deployment without assuming that the user has the sources and/or knows how to change them and/or has the ability to recompile the application is the capability that this proposal enables. It is a somewhat basic security control most other TLS libraries (outside the Go ecosystem) offer. |
There are two groups of people, on one hand you have the system administrators (IT staff) that are responsible for ensuring that the deployed systems work together, according to requirements (PCI-DSS, FIPS, CC), and on the other hand you have users, that sometimes do want to override the settings, but most often that not, just don't want to think about it. And since go is fairly new, and with little baggage, there generally are no interoperability issues, so "language default" is generally good enough, but even now there are situations where that changes, like with RSA key exchange ciphersuites. There definitely will be deployments that do depend on them. |
In addition to the disk concerns, the "Using the Configuration" section seems to change the defaults but does nothing for programs that are explicitly configuring other settings themselves. If this is about sysadmin security policy, it seems like it should be able to force specific settings, not just change defaults. I'm not sure what the path forward here is. |
The admins set the expected policy, but applications generally always need to have the last say because they may have specific reason to make an exception. In theory you may have a "default" policy and an "enforced" policy, but while having a "default" policy is sufficient, only having an "enforced" policy is detrimental as it will either force to relax it for all applications when an exception is needed or it breaks applications that need specific exceptions. In my experience with Fedora/RHEL Crypto Policy, setting defaults is sufficient to raise the general level of security via policy without impacting adversely most applications. |
As @rolandshoemaker said, we try really hard to avoid "action at a distance" with global configuration changing the local behavior of packages. We also generally try to abstract from the environment to provide reproducible behavior across platforms and, although it is not always possible (i.e. Linux root stores), we're very reticent to do unexpected reads from disk at runtime. Such reads might actually be unexpected, and if they lead to relaxing the defaults might be seen as security-relevant unexpected behavior. It is my understanding you already carry a set of patches to the standard library. Maybe we could move all the functions that determine the defaults of crypto/tls to a single, low-churn file such as |
what if this was some sort of feature that package builders can opt in to ? |
Since the behavior is likely to be different per-packager, and packagers usually have robust methods to apply patches, moving the defaults to |
I was not thinking about distro-specific behaviors, but one overloading behavior established by upstream but not active by default, activated via feature/config flag. Basically whoever is building downstream can opt into it, but it is not enabled by default? Per distro patching is kind of last resort, and I am pretty sure there are ISVs that would like the behavior w/o having to patch their tooling to achieve it. |
This would basically be enabled via build tag.
I agree, I think that this would be a viable solution and could be easily done downstream if this feature isn't enabled via an opt-in mechanism using build tags. I also appreciate the simplicity of Go by default and we don't want to disrupt that with this feature. |
It sounds like moving the relevant definitions to defaults.go so that vendors can replace them more easily is the best we can do right now, in which case this would be a likely decline. |
Filed #65265 for creating defaults.go, which doesn't need to be a proposal. |
Change https://go.dev/cl/558375 mentions this issue: |
Based on the discussion above, this proposal seems like a likely decline. |
Some default values are only used when building with the boringcrypto flag. Do we need another file for borrowing like default_boring.go? |
If the defaults are currently //go:build boringcrypto then it's fine to have a defaults_boring.go as well. |
No change in consensus, so declined. |
Change https://go.dev/cl/587296 mentions this issue: |
Fixes #65265 Updates #60790 Change-Id: Iaa5f475d614d3ed87f091c93a3f888b7eb3433f2 Reviewed-on: https://go-review.googlesource.com/c/go/+/587296 Auto-Submit: Filippo Valsorda <[email protected]> Reviewed-by: Roland Shoemaker <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]> Reviewed-by: Derek Parker <[email protected]>
Abstract
This proposal introduces a new mechanism for configuring the standard library default crypto/tls.Config settings using a file on disk. The addition of this on-disk configuration mechanism enables consistent and auditable cryptographic policies to be deployed at scale. This configuration file would be scoped to only the configuration of the crypto/tls default ciphers, curves, and min/max TLS versions allowed. Allowing for this type of on-disk configuration will give those deploying Go applications using the standard library TLS stack greater control over the cryptographic settings used by an application, especially when the one deploying the software is not in direct control of the source code.
Background
Many operating systems allow for the creation of on-disk cryptographic policies which are then consumed by processes running on that system in order to apply default system-wide configuration [1][2]. Allowing for this type of centralized configuration enables those on the operations side to have peace of mind knowing that their systems are secure and auditable.
Proposal
This proposal describes both a way to read an on-disk configuration file and subsequently apply that configuration via the
Config
object by leveraging the unexported methods of thatConfig
object in order to enforce the loaded cryptographic policy. This section will describe the technical details of the implementation.Configuration format
The on-disk configuration file will be a JSON file, allowing use of the standard library
encoding/json
package to easily read and parse the file.Locating the On-Disk Configuration
This proposal introduces two ways to specify the location of the on disk configuration file. The first would be by way of the environment variable
GOTLSCONFIG
having been set to a full path to the configuration file, which would then be used to set the value of a variable within thecrypto/tls
package to be used to load and parse the configuration. The second option is to specify the path directly via-ldflags=”-X crypto/tls.configFilepath=/path/to/config.json”
.Loading the Configuration From Disk
The configuration would be read and parsed using the
encoding/json
package and would be used to set an internal default configuration variable.Using the Configuration
The internal configuration would be applied automatically to the lists of default curves, signature algorithms and cipher suites, like so:
The configuration would also be applied to any user-created config object via a method
(c *Config) applyAlgorithmPolicy()
. This would be called when initializing a new TLS server or client, and would be used to enforce the on-disk policy for custom config objects created by users.Rationale
This approach is a non-invasive way to ensure any Go application using the standard library TLS implementation can be configured using an on-disk cryptographic configuration file. An alternative implementation would be to create an external package which could read and parse a configuration file and produce a corresponding
tls.Config
object, however that approach is only applicable to code you have access to modify. For those wishing to apply a consistent configuration across all applications on a given system, this alternative solution would still fall short.Compatibility
This change would maintain backward compatibility by skipping any newly introduced code path in the absence of an on-disk configuration.
Implementation
There is a WIP implementation from a coworker that may be helpful to look at while considering this proposal [3].
The representation of the configuration would be:
Along with a parsed policy object:
Then, within the
crypto/tls
package there would be an unexported variable named something along the lines ofpolicy
which would be a pointer to the abovealgorithmPolicy
struct. If that variable is non-nil it will be used to provide default configuration values.This policy would be loaded via an init function in the
crypto/tls
package, populating the aforementioned unexported variables. This would apply the policy to all internal defaults such as curves, signature algorithms and cipher suites. Additionally, when a user passes a config object intotls.Server
ortls.Client
, the implementation would callconfig.applyAlgorithmPolicy
to ensure that the policy is enforced.Open Issues
None.
Links
1: https://access.redhat.com/articles/3666211
2: https://manpages.ubuntu.com/manpages/focal/en/man7/crypto-policies.7.html
3: master...ueno:go:wip/tls-policy
The text was updated successfully, but these errors were encountered: