...
Internally, simpkv constructs a plugin object for each unique backend, and uses the plugin object to interface with it corresponding backend. When a simpkv::*
function is called, an internal adapter calls the plugin’s corresponding API method with normalized arguments to affect the operation. The adapter then (de)normalizes the results of the operation and reports them back to the calling simpkv::*
function.
For example, for a simpkv::put
operation using a LDAP plugin, the sequence of operations is notionally as follows:
...
Then, for a simpkv::get
operation using a LDAP plugin, the sequence of operations is notionally as follows:
...
Value normalization
One of the normalizations done by the simpkv adapter involves the value and optional, user-provided metadata associated with a key. In a simpkv::put
operation, the simpkv adapter serializes a key’s value and optional metadata into a single JSON string and then sends that to the plugin for storage in the backend. Then, after a key’s information has been retrieved by a plugin during a simpkv::get
or simpkv::list
operation, the simpkv adapter deserializes each JSON string back into the key’s value and metadata objects before serving the results back to the calling function. This encoding of a key’s value an metadata into a single string with a known, parsable format is intended to simplify backend operations.
...
Use Organizations or Organizational Units to represent folders in a key path and other grouping (e.g., environments).
Create a custom schema element with key name and value attributes to represent a key/value entry.
Construct the DN for a key/value node using each part of the key path as a Relative relative DN (RDN) with the key name followed by sequence of RDNs where each one represents a folder in the key’s path.
So, for a key path production/app1/key1
the key/value pair could be found at the DN simpkvKey=key1,ou=app1,ou=production,ou=environments,<root DN for the backend instance>
, where simpkvKey
is an attribute of a simpkvEntry
LDAP object used to store the key/value pair. Visually, this subtree in the DIT would look something like the following:
...
Unfortunately, there is a nuance in 389DS that complicates that simple mapping:
389DS instances treat DNs as case invariant strings.
So, the key paths production/app1/key1
and production/App1/Key1
both resolve to the same DN inside of 389DS, even though from simpkv’s perspective, they were intended to be distinct. This unexpected collision in the backend needs to be addressed either by simpkv or within the DIT itself.
...
The simplest design option enforces DN case invariance by requiring all the values of all attributes used in a DN for a key/value pair to be lowercase. In other words, change the experimental simpkv API to only allow lowercase letters, numerals, and ‘.
', ‘_
’, and ‘-
’ characters , and '/
' characters for all key names, folder names, and plugin instance identifiers. Then, because each key’s DN is unique and case invariant, the simple mapping scheme described in 'Design Considerations’ can be used.
...
Below is an example of the Option 1 DIT in which simpkvEntry
is a custom LDAP object class with simpkvKey
and simpkvJsonValue
attributes holding the key and value, respectively:
...
The second design option enforces DN case invariance without impacting the existing simpkv API. Its simpkv subtree has the same essential layout as that of Option 1, including the use of the ‘instances’, 'globals', and ‘environments’ grouping “folders”. However, in this design the
The LDAP plugin transforms any problematic attributes that are to be used in a DN for a key/value pair to an encoded representation (e.g., hexadecimal, Base 64) . For example, with a hexadecimal transformation, all backend instance identifiers, key names, and folder names would be represented in hex, minus the ‘
0x
’ or ‘0X
’ preface
...
. (The Puppet environment does not require transformation, as Puppet environment names must be lowercase.) So, key paths
production/app1/key1
andproduction/App1/Key1
would be mapped tosimpkvHexId=61707031,simpkvHexId=6b657931,ou=production,ou=environments,...
andsimpkvHexId=41707031,simpkvHexId=4b657931,ou=production,ou=environments,...
respectively, wheresimpkvHexId
is an attribute of both
...
an LDAP object used to represent backend identifiers/folders and
...
an LDAP object used to store the key/value pair.
**Puppet environment names are not allowed to include uppercase letters.
...
Each node with an encoded identifier
...
RDN
...
includes an attribute with the raw identifier.
...
This additional information is necessary in order to Although this means a little more data must be stored in the DIT, this extra information will support external searches of the LDAP tree using the raw backend instance identifiers, key names, and folder names.
Some ‘OrganizationalUnits’ in Option 1 would now be represented by a custom object that had encoded and raw identifier attributes.
The custom class for the key/value nodes would have encoded and raw key attributesIn other words, users can search the LDAP tree without being forced to mimic the transformations done in
simpkv::*
functions.
Below is an example of the Option 2 DIT in which
simpkvFolder
is a custom LDAP object class withsimpkvHexId
andsimpkvId
attributes holding the transformed backend identifier/folder and raw identifier/folder, respectivelysimpkvEntry
is a custom LDAP object class withsimpkvHexId
,simpkvId
andsimpkvJsonValue
attributes holding the transformed key, raw key and JSON-formatted value, respectively.
Recommendation
...
It yields a DIT that is simple to understand and navigate.
An API change is not unexpected for simp/simpkv, since it is still experimental (version < 1.0.0) and not used enabled by default.
SIMP can help users with the transition to lowercase key names for any existing simpkv key paths or
simplib::passgen
password names (whether using legacy mode or simpkv mode).Any SIMP-provided modules module that uses
simplib::passgen
can be modified to ensure the password names are downcased.The
simplib::passgen
function that uses simpkv can be modified to downcase existing password names that have any uppercase letters and then to emit a warning.In the The script SIMP will provide to import any existing simpkv key entries or
simplib::passgen
passwords into an a simpkv LDAP simpkv backend , there can be a check for uppercase letters in the destination key paths . The script can and either skip the import of the problematic entries, or convert to lowercase and warn the user of the conversion. Then, it would be up to the user to make any adjustments to their the corresponding manifests.
OID Subtree Design and Custom LDAP Schema
...
Below is the proposed SIMP OID subtree showing the parent OIDs for attributes and class objects needed for the SIMP DIT.
...
LDAP Custom Schema
simpkv DIT Option 1
...
simpkvKey
is a case-invariant string for the key . (excluding path)This is used as the final RDN of the DN for a key/value node.
simpkvJsonValue
is a case-sensitive string for the JSON-formatted value.In the future, we could write a custom syntax validator for this attribute.
...
The proposed custom schema for the simpkv DIT option 2 is shown below. It has two custom object classes and three custom attributes.
Classes:
simpkvFolder
is an object class for a node representing a backend identifier or folder.simpkvEntry
is an object class for a key/value node.
Attributes:
simpkvHexId
is an attribute that is a case-invariant, hex-encoded string for the backend identifier, folder or key
(excluding path)
This is used as the final RDN of the DN for a node.
In the future, we could write a custom syntax validator for this attribute.
simpkvId
is an attribute that is the raw, case-sensitive string for a backend identifier, folder or key
(excluding path)
simpkvJsonValue
is an attribute that is a case-sensitive string for a JSON-formatted value in a key/value node.In the future, we could write a custom syntax validator for this attribute.
Code Block |
---|
################################################################################ # dn: cn=schema # ################################################################################ # attributeTypes: ( 1.3.6.1.4.1.47012.1.1.1.1.1.1 NAME 'simpkvHexId' DESC 'hex-encoded backend instance, folder, or key name' SUP name SINGLE-VALUE X-ORIGIN 'SIMP simpkv' ) # ################################################################################ # attributeTypes: ( 1.3.6.1.4.1.47012.1.1.1.1.1.2 NAME 'simpkvId' DESC 'backend instance, key or folder name' EQUALITY caseExactMatch SUBSTR caseExactSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'SIMP simpkv' ) # ################################################################################ # attributeTypes: ( 1.3.6.1.4.1.47012.1.1.1.1.1.3 NAME 'simpkvJsonValue' DESC 'JSON-formatted value' EQUALITY caseExactMatch SUBSTR caseExactSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'SIMP simpkv' ) # ################################################################################ # objectClasses: ( 1.3.6.1.4.1.47012.1.1.1.1.2.1 NAME 'simpkvEntry' DESC 'simpkv entry' SUP top STRUCTURAL MUST ( simpkvHexId $ simpkvId $ simpkvJsonValue ) X-ORIGIN 'SIMP simpkv' ) # ################################################################################ # objectClasses: ( 1.3.6.1.4.1.47012.1.1.1.1.2.2 NAME 'simpkvFolder' DESC 'simpkv folder in which simpKvHexId represents the relative folder name in hex in the DN' SUP top STRUCTURAL MUST ( simpkvHexId $ simpkvId ) X-ORIGIN 'SIMP simpkv' ) |
...
Plugins are written in Ruby and implement the simpkv plugin API.
Plugins must be multi-thread safe.
Plugins must be written to provide Puppet-environment isolation when executed on the puppetserver.
Manifests that use
simpkv::*
functions must be able to be compiled withpuppet agent
,puppet apply
or Bolt commands. This means the plugin code will run in JRuby in the puppetserver, run in the Ruby installed with puppet-agent, or run using the Bolt user’s Ruby into which the puppet gem is installed.
...