mirror of
				https://github.com/ansible-collections/community.general.git
				synced 2025-10-24 21:14:00 -07:00 
			
		
		
		
	[PR #8952/24f2b980 backport][stable-9] passwordstore: Support subkey creation and update (#8996)
passwordstore: Support subkey creation and update (#8952)
(cherry picked from commit 24f2b980b7)
Co-authored-by: Manuel Luzarreta <mluzarreta.pro@pm.me>
	
	
This commit is contained in:
		
					parent
					
						
							
								73362a1e43
							
						
					
				
			
			
				commit
				
					
						71d8109275
					
				
			
		
					 2 changed files with 73 additions and 14 deletions
				
			
		|  | @ -0,0 +1,2 @@ | |||
| minor_changes: | ||||
|     - passwordstore lookup plugin - add subkey creation/update support (https://github.com/ansible-collections/community.general/pull/8952). | ||||
|  | @ -14,7 +14,7 @@ DOCUMENTATION = ''' | |||
|     short_description: manage passwords with passwordstore.org's pass utility | ||||
|     description: | ||||
|       - Enables Ansible to retrieve, create or update passwords from the passwordstore.org pass utility. | ||||
|         It also retrieves YAML style keys stored as multilines in the passwordfile. | ||||
|         It can also retrieve, create or update YAML style keys stored as multilines in the passwordfile. | ||||
|       - To avoid problems when accessing multiple secrets at once, add C(auto-expand-secmem) to | ||||
|         C(~/.gnupg/gpg-agent.conf). Where this is not possible, consider using O(lock=readwrite) instead. | ||||
|     options: | ||||
|  | @ -33,11 +33,11 @@ DOCUMENTATION = ''' | |||
|         env: | ||||
|           - name: PASSWORD_STORE_DIR | ||||
|       create: | ||||
|         description: Create the password if it does not already exist. Takes precedence over O(missing). | ||||
|         description: Create the password or the subkey if it does not already exist. Takes precedence over O(missing). | ||||
|         type: bool | ||||
|         default: false | ||||
|       overwrite: | ||||
|         description: Overwrite the password if it does already exist. | ||||
|         description: Overwrite the password or the subkey if it does already exist. | ||||
|         type: bool | ||||
|         default: false | ||||
|       umask: | ||||
|  | @ -53,7 +53,9 @@ DOCUMENTATION = ''' | |||
|         type: bool | ||||
|         default: false | ||||
|       subkey: | ||||
|         description: Return a specific subkey of the password. When set to V(password), always returns the first line. | ||||
|         description: | ||||
|           - By default return a specific subkey of the password. When set to V(password), always returns the first line. | ||||
|           - With O(overwrite=true), it will create the subkey and return it. | ||||
|         type: str | ||||
|         default: password | ||||
|       userpass: | ||||
|  | @ -64,7 +66,7 @@ DOCUMENTATION = ''' | |||
|         type: integer | ||||
|         default: 16 | ||||
|       backup: | ||||
|         description: Used with O(overwrite=true). Backup the previous password in a subkey. | ||||
|         description: Used with O(overwrite=true). Backup the previous password or subkey in a subkey. | ||||
|         type: bool | ||||
|         default: false | ||||
|       nosymbols: | ||||
|  | @ -189,6 +191,17 @@ tasks.yml: | | |||
|     vars: | ||||
|       mypassword: "{{ lookup('community.general.passwordstore', 'example/test', missing='create')}}" | ||||
| 
 | ||||
|   - name: >- | ||||
|       Create a random 16 character password in a subkey. If the password file already exists, just add the subkey in it. | ||||
|       If the subkey exists, returns it | ||||
|     ansible.builtin.debug: | ||||
|       msg: "{{ lookup('community.general.passwordstore', 'example/test', create=true, subkey='foo') }}" | ||||
| 
 | ||||
|   - name: >- | ||||
|       Create a random 16 character password in a subkey. Overwrite if it already exists and backup the old one. | ||||
|     ansible.builtin.debug: | ||||
|       msg: "{{ lookup('community.general.passwordstore', 'example/test', create=true, subkey='user', overwrite=true, backup=true) }}" | ||||
| 
 | ||||
|   - name: Prints 'abc' if example/test does not exist, just give the password otherwise | ||||
|     ansible.builtin.debug: | ||||
|       var: mypassword | ||||
|  | @ -411,15 +424,48 @@ class LookupModule(LookupBase): | |||
| 
 | ||||
|     def update_password(self): | ||||
|         # generate new password, insert old lines from current result and return new password | ||||
|         # if the target is a subkey, only modify the subkey | ||||
|         newpass = self.get_newpass() | ||||
|         datetime = time.strftime("%d/%m/%Y %H:%M:%S") | ||||
|         subkey = self.paramvals["subkey"] | ||||
| 
 | ||||
|         if subkey != "password": | ||||
| 
 | ||||
|             msg_lines = [] | ||||
|             subkey_exists = False | ||||
|             subkey_line = "{0}: {1}".format(subkey, newpass) | ||||
|             oldpass = None | ||||
| 
 | ||||
|             for line in self.passoutput: | ||||
|                 if line.startswith("{0}: ".format(subkey)): | ||||
|                     oldpass = self.passdict[subkey] | ||||
|                     line = subkey_line | ||||
|                     subkey_exists = True | ||||
| 
 | ||||
|                 msg_lines.append(line) | ||||
| 
 | ||||
|             if not subkey_exists: | ||||
|                 msg_lines.insert(2, subkey_line) | ||||
| 
 | ||||
|             if self.paramvals["timestamp"] and self.paramvals["backup"] and oldpass and oldpass != newpass: | ||||
|                 msg_lines.append( | ||||
|                     "lookup_pass: old subkey '{0}' password was {1} (Updated on {2})\n".format( | ||||
|                         subkey, oldpass, datetime | ||||
|                     ) | ||||
|                 ) | ||||
| 
 | ||||
|             msg = os.linesep.join(msg_lines) | ||||
| 
 | ||||
|         else: | ||||
|             msg = newpass | ||||
| 
 | ||||
|             if self.paramvals['preserve'] or self.paramvals['timestamp']: | ||||
|                 msg += '\n' | ||||
|                 if self.paramvals['preserve'] and self.passoutput[1:]: | ||||
|                     msg += '\n'.join(self.passoutput[1:]) + '\n' | ||||
|                 if self.paramvals['timestamp'] and self.paramvals['backup']: | ||||
|                     msg += "lookup_pass: old password was {0} (Updated on {1})\n".format(self.password, datetime) | ||||
| 
 | ||||
|         try: | ||||
|             check_output2([self.pass_cmd, 'insert', '-f', '-m', self.passname], input=msg, env=self.env) | ||||
|         except (subprocess.CalledProcessError) as e: | ||||
|  | @ -431,13 +477,21 @@ class LookupModule(LookupBase): | |||
|         # use pwgen to generate the password and insert values with pass -m | ||||
|         newpass = self.get_newpass() | ||||
|         datetime = time.strftime("%d/%m/%Y %H:%M:%S") | ||||
|         subkey = self.paramvals["subkey"] | ||||
| 
 | ||||
|         if subkey != "password": | ||||
|             msg = "\n\n{0}: {1}".format(subkey, newpass) | ||||
|         else: | ||||
|             msg = newpass | ||||
| 
 | ||||
|         if self.paramvals['timestamp']: | ||||
|             msg += '\n' + "lookup_pass: First generated by ansible on {0}\n".format(datetime) | ||||
| 
 | ||||
|         try: | ||||
|             check_output2([self.pass_cmd, 'insert', '-f', '-m', self.passname], input=msg, env=self.env) | ||||
|         except (subprocess.CalledProcessError) as e: | ||||
|             raise AnsibleError('exit code {0} while running {1}. Error output: {2}'.format(e.returncode, e.cmd, e.output)) | ||||
| 
 | ||||
|         return newpass | ||||
| 
 | ||||
|     def get_passresult(self): | ||||
|  | @ -525,7 +579,10 @@ class LookupModule(LookupBase): | |||
|             self.parse_params(term)   # parse the input into paramvals | ||||
|             with self.opt_lock('readwrite'): | ||||
|                 if self.check_pass():     # password exists | ||||
|                     if self.paramvals['overwrite'] and self.paramvals['subkey'] == 'password': | ||||
|                     if self.paramvals['overwrite']: | ||||
|                         with self.opt_lock('write'): | ||||
|                             result.append(self.update_password()) | ||||
|                     elif self.paramvals["subkey"] != "password" and not self.passdict.get(self.paramvals['subkey']):  # password exists but not the subkey | ||||
|                         with self.opt_lock('write'): | ||||
|                             result.append(self.update_password()) | ||||
|                     else: | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue