-
Notifications
You must be signed in to change notification settings - Fork 26
Tls session tags #135
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
Merged
Merged
Tls session tags #135
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Automake warns that addprefix is a non-POSIX variable name when processing the systemd unit installation logic. The addprefix function is a GNU make extension, limiting portability to build environments that use other make implementations. A shell for loop iterates over the unit file list at install time, prefixing each filename with $(srcdir) as required for out-of-tree builds. This achieves the same result while remaining compatible with POSIX make, eliminating the automake warning and improving build system portability. Fixes: b922431 ("systemd: Fix out-of-tree builds") Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
The Doxyfile configuration file in the docs/ directory is generated during the build process, not maintained in version control. When the build system creates this file, git status incorrectly reports it as an untracked change, cluttering the working directory state. Adding docs/Doxyfile to .gitignore prevents this generated artifact from appearing in status output, keeping the repository's tracked and untracked file lists accurate. Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Runtime configuration updates require restarting the tlshd daemon, causing service interruption. Long-running systems benefit from configuration reload without service downtime. The config subsystem now stores the pathname of the configuration file loaded during initialization. A new tlshd_config_reload() function rereads this file and updates debug levels and keyring links immediately. The main event loop catches SIGHUP and SIGUSR1 through the existing signalfd mechanism, invokes the reload function, and continues polling for netlink messages rather than terminating. Configuration reload enables operators to adjust debug verbosity and keyring associations without dropping active TLS sessions. SIGINT and SIGTERM continue to terminate the daemon cleanly. Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Now that tlshd has proper signal handling, add documentation of the threading model to help guide developers adding new features to tlshd. The current fork-per-request architecture and single-threaded event loop employs poll(2), multiplexes netlink messages and signals, and child processes inherit copy-on-write snapshots of configuration data. This makes pthread synchronization primitives unnecessary, and puts a high wall between threads working on each handshake. Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
An upcoming new feature requires configuration via YAML documents. LibYAML provides the parser needed to process those configuration files at runtime. This change adds the configure.ac check to ensure the library is present during the build process. Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
The session tagging subsystem enables kernel TLS consumers to perform authorization checks based on peer certificate content. After certificate chain validation succeeds, tags matching specific certificate field values are returned to the kernel with the handshake result. The kernel consumer can then grant or deny access to resources based on these tags. This change adds subsystem lifecycle management and introduces a new source file, tags.c, containing stub implementations that will be populated with YAML parsing and certificate matching logic in subsequent patches. Tags initialization occurs in main.c after configuration parsing completes, rather than being embedded within tlshd_config_init. This separation follows the Single Responsibility Principle: config.c focuses on configuration file parsing, while main.c handles initialization sequencing. Tags shutdown occurs in main.c before configuration cleanup during daemon termination. Configuration reload coordination remains in config.c, as reload is an operational feature rather than initialization. When SIGHUP triggers configuration reload, config.c reloads both its own configuration and the tags configuration to maintain consistency. The tags directory path is currently hard-coded to /etc/tlshd/tags.d but might become a configuration file option in the future.
Administrators need documentation to configure and deploy the session tagging mechanism. Without guidance on the YAML filter syntax, certificate field matching rules, and tag assignment behavior, operators cannot leverage session tags for policy decisions. This introduces tls-session-tags(7), which provides an overview of how tlshd scans peer certificate fields during handshake verification and assigns tags based on conditions defined in /etc/tlshd/tags.d/. The man page establishes the conceptual foundation: tags enable kernel TLS consumers to make authorization decisions based on certificate content rather than relying solely on CA-based trust. Subsequent patches will populate the man page with detailed configuration syntax, filter examples, and operational guidance. The build system changes add man7 support to accommodate this new documentation category. Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Session tag assignment requires filtering peer certificates, but no mechanism exists to specify which certificate fields to examine or how to match values within them. This prevents administrators from defining meaningful session tags based on certificate content. Each filter type defines a specific certificate field or derived property that can be matched during session establishment. The implementation uses a static table of twelve filter types covering RFC 5280 certificate fields (signatureAlgorithm, version, serialNumber, signature, issuer, notBefore, notAfter, subject), standard extensions (keyUsage, extendedKeyUsage), and locally computed properties (fingerprint, selfSigned). Each entry in the table includes a name following x509 dotted notation, plus function pointers for validation and matching operations that will be added in subsequent patches. At daemon startup, a hash table indexes these filter types by name, providing O(1) lookup when parsing tag configuration files. This lookup path will be exercised when administrators create filters referencing these type names. Testing: daemon starts successfully with new hash initialization. Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
TLS session tag definitions are to be stored in YAML files. These files may be edited by hand, or for better UX, an assistant tool might be constructed to make it easier to handle tags. A parser is required to read these configuration files and construct the internal data structures that represent filtering rules for session tags. This commit introduces a finite state machine parser built on libyaml that validates YAML document structure in tag definition files. The FSM tracks document boundaries (stream start/end, document start/end, mapping start/end) and ensures input conforms to expected YAML grammar. Directory scanning locates all .yml and .yaml files in the configuration directory and processes each through the parser. The parser currently validates only document structure. Subsequent commits will extend the FSM to recognize tag definition scalars and construct the filtering data structures. This incremental approach allows verification of the parsing framework before adding semantic processing. A debug helper translates libyaml event types into human-readable symbols for troubleshooting YAML parsing failures. The FSM state transition tables are structured to simplify addition of new states as tag definition parsing logic is implemented. Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Session tag assignment requires filters that specify which certificate fields to examine and how to match their values, but the YAML parser added previously validates only document structure without extracting filter specifications. This prevents the daemon from constructing the filter rules that govern tag assignment. This commit extends the finite state machine with nine new states that parse filter definitions from YAML input. Each filter specification includes a unique name, a filter type (referencing the type table from a prior commit), and type-specific arguments such as wildcard patterns for string matching or purpose masks for keyUsage validation. The parser validates filter names against a regex constraint limiting characters to alphanumerics, hyphens, and underscores. Parsed filters populate a hash table indexed by name, providing O(1) lookup during subsequent tag processing. The FSM transitions handle three argument classes: pattern-based filters store a GLib pattern spec for wildcard matching, purpose-based filters accumulate a bitmask of GNUTLS keyUsage flags, and time-based filters (parsing not yet implemented) will validate temporal constraints. Each filter undergoes type-specific validation before insertion into the hash table, ensuring malformed specifications are rejected at parse time rather than during handshake processing. A subsequent patch will add tag definitions that reference these parsed filters. Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Session tag assignment requires a collection of tags, each associating a name with a list of filters that must match for the tag to apply to a TLS session, but the parser implemented previously extracts only filter definitions from YAML input without recognizing tag specifications. This prevents the daemon from constructing the complete rule set needed to assign tags during handshake completion. This extends the finite state machine with six new states that parse tag definitions from YAML input. Each tag specification includes a unique name (validated against the same alphanumeric plus hyphen/underscore regex used for filter names) and a list of filter references. Filter names may be prefixed with "not " to invert their match semantics. The parser separates inverted and non-inverted filter references into distinct pointer arrays, simplifying the matching logic that will be added in subsequent patches. Parsed tags populate a hash table indexed by name, providing O(1) lookup when kernel consumers query available tags. Tag specifications reference filters by name only, requiring those filters to exist in the filter hash table populated by earlier parsing. A subsequent patch will add the matching logic that applies these filter lists to incoming peer certificates during handshake completion and attaches matching tag names to the resulting TLS session. Parse errors in tag configuration files are reported but do not prevent daemon startup, allowing partial tag definitions to remain available even when some configuration files contain errors. Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Authorization for NFS clients on TLS connections requires per-peer access control that kernel mechanisms alone cannot provide. The in-kernel LSM and NFS server access controls can only examine data in the socket structure; x.509 certificate fields presented during the TLS handshake remain inaccessible to those subsystems. Filter-based tagging provides the needed mechanism. An x.509 peer certificate passes through a set of administrator-defined filters read from /etc/tlshd/tags.d at start-up. Each tag consists of one or more filter expressions that match against specific x.509 fields. When all of a tag's filters match, that tag name becomes associated with the TLS session. The new tlshd_tags_match_session() function parses the client's certificate after a successful handshake and applies each tag's filters. Pattern filters use Glib pattern matching. Time filters compare certificate validity windows against specified points in time. Purpose and key usage filters apply bitmask operations. Filters are composable: all non-inverted filters in a tag must match for the tag to apply, while any matched inverted filter disqualifies the tag. A subsequent change will transmit the matched tag list to the kernel upon handshake completion, enabling kernel-side policy enforcement based on certificate properties. Suggested-by: Benjamin Coddington <bcodding@redhat.com> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
A recent commit added documentation describing the concurrency architecture for tlshd. This commit adds Doxygen documentation pages in tags.c that references the primary threading documentation and explains tag-specific concurrency properties. It documents that the parent process handles configuration reload atomically during signal processing, while child processes perform only read operations on inherited hash tables. This design ensures that no concurrent modification can occur. Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Transmitting session tags to the kernel upon handshake completion requires a new netlink attribute to carry each tag name. The kernel handshake uAPI header defines HANDSHAKE_A_DONE_TAG for this purpose, but the tlshd copy of that header predates this addition. Synchronize the local netlink.h with the kernel's include/uapi/linux/handshake.h by adding the HANDSHAKE_A_DONE_TAG attribute definition. A subsequent change will use this attribute to return matched tag names in the DONE netlink command. Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
After a successful TLS handshake, the daemon has matched the peer certificate against administrator-defined filters and accumulated a list of tag names. However, without a mechanism to deliver these tags to the kernel, kernel-side consumers cannot perform policy decisions based on certificate properties. Extend the DONE netlink response to include matched tag names. The new tlshd_tags_for_each_matched() function iterates over the global tag hash table and invokes a callback for each tag marked as matched. The tlshd_genl_put_tag() callback serializes each tag name as a HANDSHAKE_A_DONE_TAG string attribute in the netlink message. Multiple tags may match a single session; each appears as a separate attribute in the response. Kernel TLS consumers that receive this response can examine these tag names to enforce access control policies that depend on certificate properties inaccessible at the socket layer. Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
The session tagging subsystem reads filter and tag definitions from YAML files in /etc/tlshd/tags.d/, but no installation target creates this directory. Administrators would need to create it manually before session tagging could function. Add the tags.d directory to the Makefile.am install target so that "make install" creates it alongside the existing /etc/tlshd/ configuration directory. Include a tags.example file demonstrating the YAML syntax for filter and tag definitions. The example illustrates pattern-based filters matching issuer and subject fields, keyUsage filters validating certificate purposes, and tag definitions that combine multiple filters. Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
TLS session tags require libyaml for parsing definition files, but not all deployment environments provide this library or require the tagging functionality. Building session tags unconditionally would impose an unnecessary dependency on environments that do not use this feature. Introduce --enable-session-tags to make session tag support optional. When disabled (the default), tags.c is excluded from the build, libyaml is not required as a dependency, and the /etc/tlshd/tags.d directory is not created during installation. Stub inline functions in tlshd.h ensure call sites compile without modification when the feature is absent, returning success values that allow normal daemon operation without tag processing. The default setting is disabled to prevent handshake failures on kernels that do not implement TLS session tags. When a DONE downcall contains netlink arguments the kernel does not recognize, the kernel discards the entire downcall rather than processing it with the unsupported arguments ignored. On such kernels, enabling session tags would cause tlshd to send DONE downcalls with tag arguments, triggering this behavior and breaking handshake completion. Requiring explicit opt-in ensures tlshd operates correctly across kernel versions by default. The CI workflow configurations are updated to enable session tags so that the tagging code receives build and test coverage in automated checks. Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
The SIGHUP handler invokes tlshd_tags_config_reload(), which previously returned success without performing any action. This created a false expectation for administrators that sending SIGHUP would reload the tags configuration from disk. Actual reload is now performed atomically by constructing new hash tables, loading the updated configuration files, and replacing the global tables only upon successful parsing. If parsing fails at any stage, the new tables are discarded and the existing configuration remains active. This ensures that a malformed configuration file cannot leave the subsystem in an inconsistent state. The implementation saves pointers to the current filter and tag hash tables, clears the global pointers, initializes fresh hash tables, and attempts to parse the tags directory. On success, the old tables are destroyed and the new configuration takes effect. On failure, the fresh tables are destroyed, the saved pointers are restored, and an error is logged indicating that the previous configuration is retained. Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Older kernels reject the entire HANDSHAKE_CMD_DONE message when it contains netlink attributes they do not recognize, rather than ignoring unknown attributes. This causes handshakes to fail on kernels that lack support for optional features such as session tags or remote peer identity reporting. To prevent this failure mode, tlshd now probes the kernel at startup to determine which optional attributes are supported. A generic probe function sends test messages containing each optional attribute and observes whether the kernel accepts the attribute type. Results are cached in a capability structure for consultation before constructing messages. The probe mechanism sends a minimally-valid message for each command type, including required attributes but with values that will cause the kernel to reject the operation for reasons other than attribute support. For HANDSHAKE_CMD_DONE, the probe supplies an invalid socket descriptor, which the kernel rejects after successfully parsing all attributes. Error codes distinguish between "attribute not supported" and "operation failed for other reasons." Capability detection occurs in tlshd_genl_dispatch after joining the handshake multicast group but before entering the event loop. Detected capabilities are logged at notice level to inform administrators which features are available. The DONE command consults capability flags before adding optional attributes, ensuring messages contain only attributes the kernel will accept. This design scales to additional optional attributes: adding a new feature requires appending one field to the capability structure, adding one probe call, and checking the flag before using the attribute. No per-attribute detection logic or version comparisons are needed. Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
8833823 to
578d5ae
Compare
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This series introduces TLS session tagging, a mechanism that enables kernel-side authorization decisions based on x.509 certificate content presented during TLS handshakes. After successful certificate chain validation, tlshd applies administrator-defined filters from /etc/tlshd/tags.d to the peer certificate, examining specific fields (subject, issuer, keyUsage, serialNumber, validity periods, and other RFC 5280 properties) and assigning tag names when all filters in a tag definition match. These matched tag names are returned to the kernel via new HANDSHAKE_A_DONE_TAG netlink attributes, allowing kernel TLS consumers to enforce per-peer access control policies that cannot be implemented using only socket-layer data visible to in-kernel LSM and NFS server subsystems. The feature is optional via --enable-session-tags to prevent handshake failures on older kernels that reject unknown netlink attributes; when enabled, kernel capability detection probes for tag attribute support at startup before attempting to use it. Configuration reload via SIGHUP is atomic: new filter and tag hash tables are constructed, populated from YAML files, and swapped in only upon successful parsing, ensuring malformed configuration cannot leave the subsystem inconsistent. The implementation leverages the existing fork-per-request architecture where child processes inherit copy-on-write snapshots of configuration data, eliminating the need for synchronization primitives while maintaining safe concurrent access.