1818import java .nio .charset .StandardCharsets ;
1919import java .util .HashMap ;
2020import java .util .Map ;
21- import java .util .logging .Logger ;
2221
23- /**
24- * <p>The Vault driver class, the primary interface through which dependent applications will
25- * access Vault.</p>
26- *
27- * <p>This driver exposes a DSL, compartmentalizing the various endpoints of the HTTP API (e.g.
28- * "/", "sys/init", "sys/seal") into separate implementation classes (e.g. <code>Logical</code>,
29- * <code>Init</code>, etc).</p>
30- *
31- * <p>Example usage:</p>
32- *
33- * <blockquote>
34- * <pre>{@code
35- * final VaultConfig config = new VaultConfig
36- * .address("http://127.0.0.1:8200")
37- * .token("eace6676-4d78-c687-4e54-03cad00e3abf")
38- * .build();
39- * final Vault vault = new Vault(config);
40- *
41- * ...
42- *
43- * final Map<String, String> secrets = new HashMap<String, String>();
44- * secrets.put("value", "world");
45- * secrets.put("other_value", "You can store multiple name/value pairs under a given key");
46- *
47- * final LogicalResponse writeResponse = vault
48- * .withRetries(5, 1000) // optional
49- * .logical()
50- * .write("secret/hello", secrets);
51- *
52- * ...
53- *
54- * final String value = vault.logical()
55- * .read("secret/hello")
56- * .getData().get("value");
57- * }</pre>
58- * </blockquote>
59- */
60- public class Vault {
22+ public interface Vault {
6123
62- private final VaultConfig vaultConfig ;
63- private Logger logger = Logger .getLogger (Vault .class .getCanonicalName ());
64-
65- /**
66- * Construct a Vault driver instance with the provided config settings.
67- *
68- * @param vaultConfig Configuration settings for Vault interaction (e.g. server address, token,
69- * etc) If the VaultConfig Engine version path map is not supplied in the config, default to
70- * global KV engine version 2.
71- */
72- public Vault (final VaultConfig vaultConfig ) {
73- this .vaultConfig = vaultConfig ;
74- if (this .vaultConfig .getNameSpace () != null && !this .vaultConfig .getNameSpace ().isEmpty ()) {
75- logger .info (String .format (
76- "The NameSpace %s has been bound to this Vault instance. Please keep this in mind when running operations." ,
77- this .vaultConfig .getNameSpace ()));
78- }
79- if (this .vaultConfig .getSecretsEnginePathMap ().isEmpty ()
80- && this .vaultConfig .getGlobalEngineVersion () == null ) {
81- logger .info (
82- "Constructing a Vault instance with no provided Engine version, defaulting to version 2." );
83- this .vaultConfig .setEngineVersion (2 );
84- }
24+ static Vault create (VaultConfig vaultConfig ){
25+ return new VaultImpl (vaultConfig );
8526 }
8627
8728 /**
@@ -93,19 +34,8 @@ public Vault(final VaultConfig vaultConfig) {
9334 * @param engineVersion Which version of the Key/Value Secret Engine to use globally (i.e. 1 or
9435 * 2)
9536 */
96- public Vault (final VaultConfig vaultConfig , final Integer engineVersion ) {
97- if (engineVersion < 1 || engineVersion > 2 ) {
98- throw new IllegalArgumentException (
99- "The Engine version must be '1' or '2', the version supplied was: '"
100- + engineVersion + "'." );
101- }
102- vaultConfig .setEngineVersion (engineVersion );
103- this .vaultConfig = vaultConfig ;
104- if (this .vaultConfig .getNameSpace () != null && !this .vaultConfig .getNameSpace ().isEmpty ()) {
105- logger .info (String .format (
106- "The Namespace %s has been bound to this Vault instance. Please keep this in mind when running operations." ,
107- this .vaultConfig .getNameSpace ()));
108- }
37+ static Vault create (final VaultConfig vaultConfig , final Integer engineVersion ) {
38+ return new VaultImpl (vaultConfig , engineVersion );
10939 }
11040
11141 /**
@@ -121,31 +51,10 @@ public Vault(final VaultConfig vaultConfig, final Integer engineVersion) {
12151 * fallback.
12252 * @throws VaultException If any error occurs
12353 */
124- public Vault (final VaultConfig vaultConfig , final Boolean useSecretsEnginePathMap ,
54+ static Vault create (final VaultConfig vaultConfig , final Boolean useSecretsEnginePathMap ,
12555 final Integer globalFallbackVersion )
12656 throws VaultException {
127- this .vaultConfig = vaultConfig ;
128- if (this .vaultConfig .getNameSpace () != null && !this .vaultConfig .getNameSpace ().isEmpty ()) {
129- logger .info (String .format (
130- "The Namespace %s has been bound to this Vault instance. Please keep this in mind when running operations." ,
131- this .vaultConfig .getNameSpace ()));
132- }
133- this .vaultConfig .setEngineVersion (globalFallbackVersion );
134- if (useSecretsEnginePathMap && this .vaultConfig .getSecretsEnginePathMap ().isEmpty ()) {
135- try {
136- logger .info (
137- "No secrets Engine version map was supplied, attempting to generate one." );
138- final Map <String , String > secretsEnginePathMap = collectSecretEngineVersions ();
139- assert secretsEnginePathMap != null ;
140- this .vaultConfig .getSecretsEnginePathMap ().putAll (secretsEnginePathMap );
141- } catch (Exception e ) {
142- throw new VaultException (String .format (
143- "An Engine KV version map was not supplied, and unable to determine " +
144- "KV Engine " +
145- "version, " + "due to exception: %s" ,
146- e .getMessage () + ". Do you have admin rights?" ));
147- }
148- }
57+ return new VaultImpl (vaultConfig , useSecretsEnginePathMap , globalFallbackVersion );
14958 }
15059
15160 /**
@@ -158,30 +67,30 @@ public Vault(final VaultConfig vaultConfig, final Boolean useSecretsEnginePathMa
15867 * between retries
15968 * @return This object, with maxRetries and retryIntervalMilliseconds populated
16069 */
161- public Vault withRetries (final int maxRetries , final int retryIntervalMilliseconds ) {
162- this .vaultConfig .setMaxRetries (maxRetries );
163- this .vaultConfig .setRetryIntervalMilliseconds (retryIntervalMilliseconds );
164- return this ;
165- }
70+ Vault withRetries (final int maxRetries , final int retryIntervalMilliseconds );
16671
16772 /**
16873 * Returns the implementing class for Vault's core/logical operations (e.g. read, write).
16974 *
17075 * @return The implementing class for Vault's core/logical operations (e.g. read, write)
17176 */
172- public Logical logical () {
173- return new Logical (vaultConfig );
174- }
77+ Logical logical ();
17578
17679 /**
17780 * Returns the implementing class for operations on Vault's <code>/v1/auth/*</code> REST
17881 * endpoints
17982 *
18083 * @return The implementing class for Vault's auth operations.
18184 */
182- public Auth auth () {
183- return new Auth (vaultConfig );
184- }
85+ Auth auth ();
86+
87+ /**
88+ * Returns the implementing class for operations on Vault's <code>/v1/sys/*</code> REST
89+ * endpoints
90+ *
91+ * @return The implementing class for Vault's auth operations.
92+ */
93+ Sys sys ();
18594
18695 /**
18796 * Returns the implementing class for operations on Vault's <code>/v1/sys/*</code> REST
@@ -199,9 +108,7 @@ public Sys sys() {
199108 *
200109 * @return The implementing class for Vault's PKI secret backend.
201110 */
202- public Pki pki () {
203- return new Pki (vaultConfig );
204- }
111+ Pki pki ();
205112
206113 /**
207114 * <p>Returns the implementing class for Vault's PKI secret backend, using a custom path when
@@ -214,7 +121,7 @@ public Pki pki() {
214121 * <blockquote>
215122 * <pre>{@code
216123 * final VaultConfig config = new VaultConfig().address(...).token(...).build();
217- * final Vault vault = new Vault(config);
124+ * final Vault vault = Vault.create (config);
218125 * final PkiResponse response = vault.pki("root-ca").createOrUpdateRole("testRole");
219126 *
220127 * assertEquals(204, response.getRestResponse().getStatus());
@@ -225,112 +132,37 @@ public Pki pki() {
225132 * <code>/v1/</code> prefix
226133 * @return The implementing class for Vault's PKI secret backend.
227134 */
228- public Pki pki (final String mountPath ) {
229- return new Pki (vaultConfig , mountPath );
230- }
135+ Pki pki (final String mountPath );
231136
232- public Database database () {
233- return new Database (vaultConfig );
234- }
137+ Database database ();
235138
236- public Database database (final String mountPath ) {
237- return new Database (vaultConfig , mountPath );
238- }
139+ Database database (final String mountPath );
239140
240141 /**
241142 * @see Sys#leases()
242143 * @deprecated This method is deprecated and in future it will be removed
243144 */
244- public Leases leases () {
245- return new Leases (vaultConfig );
246- }
145+ Leases leases ();
247146
248147 /**
249148 * Returns the implementing class for Vault's debug operations (e.g. raw, health).
250149 *
251150 * @return The implementing class for Vault's debug operations (e.g. raw, health)
252151 */
253- public Debug debug () {
254- return new Debug (vaultConfig );
255- }
152+ Debug debug ();
256153
257154 /**
258155 * @see Sys#mounts()
259156 * @deprecated This method is deprecated and in future it will be removed
260157 */
261- public Mounts mounts () {
262- return new Mounts (vaultConfig );
263- }
158+ Mounts mounts ();
264159
265160 /**
266161 * @see Sys#seal()
267162 * @deprecated This method is deprecated and in future it will be removed
268163 */
269- public Seal seal () {
270- return new Seal (vaultConfig );
271- }
272-
273- /**
274- * Makes a REST call to Vault, to collect information on which secret engine version (if any) is
275- * used by each available mount point. Possibilities are:
276- *
277- * <ul>
278- * <li>"2" - A mount point running on Vault 0.10 or higher, configured to use the engine 2
279- * API</li>
280- * <li>"1" - A mount point running on Vault 0.10 or higher, configured to use the engine 1
281- * API</li>
282- * <li>"unknown" - A mount point running on an older version of Vault. Can more or less be
283- * treated as "1".</li>
284- * </ul>
285- * <p>
286- * IMPORTANT: Whichever authentication mechanism is being used with the
287- * <code>VaultConfig</code> object, that principal needs permission to access the
288- * <code>/v1/sys/mounts</code> REST endpoint.
289- *
290- * @return A map of mount points (e.g. "/secret") to secret engine version numbers (e.g. "2")
291- */
292- private Map <String , String > collectSecretEngineVersions () {
293- try {
294- final RestResponse restResponse = new Rest ()//NOPMD
295- .url (vaultConfig .getAddress () + "/v1/sys/mounts" )
296- .header ("X-Vault-Token" , vaultConfig .getToken ())
297- .header ("X-Vault-Namespace" , this .vaultConfig .getNameSpace ())
298- .header ("X-Vault-Request" , "true" )
299- .connectTimeoutSeconds (vaultConfig .getOpenTimeout ())
300- .readTimeoutSeconds (vaultConfig .getReadTimeout ())
301- .sslVerification (vaultConfig .getSslConfig ().isVerify ())
302- .sslContext (vaultConfig .getSslConfig ().getSslContext ())
303- .get ();
304- if (restResponse .getStatus () != 200 ) {
305- return null ;
306- }
307-
308- final String jsonString = new String (restResponse .getBody (), StandardCharsets .UTF_8 );
309- final Map <String , String > data = new HashMap <>();
310- final JsonObject jsonData = Json .parse (jsonString ).asObject ().get ("data" ).asObject ();
311- for (JsonObject .Member member : jsonData ) {
312- final String name = member .getName ();
313- String version = "unknown" ;
164+ Seal seal ();
314165
315- final JsonValue options = member .getValue ().asObject ().get ("options" );
316- if (options != null && options .isObject ()) {
317- final JsonValue ver = options .asObject ().get ("version" );
318- if (ver != null && ver .isString ()) {
319- version = ver .asString ();
320- }
321- }
322- data .put (name , version );
323- }
324- return data ;
325- } catch (RestException e ) {
326- System .err .print (
327- String .format ("Unable to retrieve the KV Engine secrets, due to exception: %s" ,
328- e .getMessage ()));
329- return null ;
330- }
331- }
166+ Map <String , String > getSecretEngineVersions ();
332167
333- public Map <String , String > getSecretEngineVersions () {
334- return this .collectSecretEngineVersions ();
335- }
336168}
0 commit comments