mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
allow specifying a 1Password account ID (#7308)
* allow specifying a 1p account ID * add 'version_added' field Co-authored-by: Felix Fontein <felix@fontein.de> * fix spacing Co-authored-by: Felix Fontein <felix@fontein.de> * add changelog fragment * update onepassword_raw * Remove periods. --------- Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
parent
eae7161bf0
commit
35b252c9ad
3 changed files with 51 additions and 7 deletions
3
changelogs/fragments/7308-onepassword-multi-acc.yml
Normal file
3
changelogs/fragments/7308-onepassword-multi-acc.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
minor_changes:
|
||||
- onepassword lookup plugin - introduce ``account_id`` option which allows specifying which account to use (https://github.com/ansible-collections/community.general/pull/7308).
|
||||
- onepassword_raw lookup plugin - introduce ``account_id`` option which allows specifying which account to use (https://github.com/ansible-collections/community.general/pull/7308).
|
|
@ -38,6 +38,10 @@ DOCUMENTATION = '''
|
|||
type: str
|
||||
subdomain:
|
||||
description: The 1Password subdomain to authenticate against.
|
||||
account_id:
|
||||
description: The account ID to target.
|
||||
type: str
|
||||
version_added: 7.5.0
|
||||
username:
|
||||
description: The username used to sign in.
|
||||
secret_key:
|
||||
|
@ -55,6 +59,7 @@ DOCUMENTATION = '''
|
|||
performed an initial sign in (meaning C(~/.op/config), C(~/.config/op/config) or C(~/.config/.op/config) exists), then only the
|
||||
C(master_password) is required. You may optionally specify O(subdomain) in this scenario, otherwise the last used subdomain will be used by C(op).
|
||||
- This lookup can perform an initial login by providing O(subdomain), O(username), O(secret_key), and O(master_password).
|
||||
- Can target a specific account by providing the O(account_id).
|
||||
- Due to the B(very) sensitive nature of these credentials, it is B(highly) recommended that you only pass in the minimal credentials
|
||||
needed at any given time. Also, store these credentials in an Ansible Vault using a key that is equal to or greater in strength
|
||||
to the 1Password master password.
|
||||
|
@ -93,6 +98,12 @@ EXAMPLES = """
|
|||
master_password=vault_master_password,
|
||||
username='tweety@acme.com',
|
||||
secret_key=vault_secret_key)
|
||||
|
||||
- name: Retrieve password from specific account
|
||||
ansible.builtin.debug:
|
||||
var: lookup('community.general.onepassword',
|
||||
'HAL 9000',
|
||||
account_id='abc123')
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
|
@ -119,13 +130,23 @@ from ansible_collections.community.general.plugins.module_utils.onepassword impo
|
|||
class OnePassCLIBase(with_metaclass(abc.ABCMeta, object)):
|
||||
bin = "op"
|
||||
|
||||
def __init__(self, subdomain=None, domain="1password.com", username=None, secret_key=None, master_password=None, service_account_token=None):
|
||||
def __init__(
|
||||
self,
|
||||
subdomain=None,
|
||||
domain="1password.com",
|
||||
username=None,
|
||||
secret_key=None,
|
||||
master_password=None,
|
||||
service_account_token=None,
|
||||
account_id=None,
|
||||
):
|
||||
self.subdomain = subdomain
|
||||
self.domain = domain
|
||||
self.username = username
|
||||
self.master_password = master_password
|
||||
self.secret_key = secret_key
|
||||
self.service_account_token = service_account_token
|
||||
self.account_id = account_id
|
||||
|
||||
self._path = None
|
||||
self._version = None
|
||||
|
@ -293,7 +314,9 @@ class OnePassCLIv1(OnePassCLIBase):
|
|||
|
||||
def assert_logged_in(self):
|
||||
args = ["get", "account"]
|
||||
if self.subdomain:
|
||||
if self.account_id:
|
||||
args.extend(["--account", self.account_id])
|
||||
elif self.subdomain:
|
||||
account = "{subdomain}.{domain}".format(subdomain=self.subdomain, domain=self.domain)
|
||||
args.extend(["--account", account])
|
||||
|
||||
|
@ -326,6 +349,10 @@ class OnePassCLIv1(OnePassCLIBase):
|
|||
|
||||
def get_raw(self, item_id, vault=None, token=None):
|
||||
args = ["get", "item", item_id]
|
||||
|
||||
if self.account_id:
|
||||
args.extend(["--account", self.account_id])
|
||||
|
||||
if vault is not None:
|
||||
args += ["--vault={0}".format(vault)]
|
||||
|
||||
|
@ -502,7 +529,9 @@ class OnePassCLIv2(OnePassCLIBase):
|
|||
# an interactive prompt. Only run 'op account get' after first listing accounts to see
|
||||
# if there are any previously configured accounts.
|
||||
args = ["account", "get"]
|
||||
if self.subdomain:
|
||||
if self.account_id:
|
||||
args.extend(["--account", self.account_id])
|
||||
elif self.subdomain:
|
||||
account = "{subdomain}.{domain}".format(subdomain=self.subdomain, domain=self.domain)
|
||||
args.extend(["--account", account])
|
||||
|
||||
|
@ -533,6 +562,10 @@ class OnePassCLIv2(OnePassCLIBase):
|
|||
|
||||
def get_raw(self, item_id, vault=None, token=None):
|
||||
args = ["item", "get", item_id, "--format", "json"]
|
||||
|
||||
if self.account_id:
|
||||
args.extend(["--account", self.account_id])
|
||||
|
||||
if vault is not None:
|
||||
args += ["--vault={0}".format(vault)]
|
||||
|
||||
|
@ -559,13 +592,14 @@ class OnePassCLIv2(OnePassCLIBase):
|
|||
|
||||
class OnePass(object):
|
||||
def __init__(self, subdomain=None, domain="1password.com", username=None, secret_key=None, master_password=None,
|
||||
service_account_token=None):
|
||||
service_account_token=None, account_id=None):
|
||||
self.subdomain = subdomain
|
||||
self.domain = domain
|
||||
self.username = username
|
||||
self.secret_key = secret_key
|
||||
self.master_password = master_password
|
||||
self.service_account_token = service_account_token
|
||||
self.account_id = account_id
|
||||
|
||||
self.logged_in = False
|
||||
self.token = None
|
||||
|
@ -578,7 +612,7 @@ class OnePass(object):
|
|||
for cls in OnePassCLIBase.__subclasses__():
|
||||
if cls.supports_version == version.split(".")[0]:
|
||||
try:
|
||||
return cls(self.subdomain, self.domain, self.username, self.secret_key, self.master_password, self.service_account_token)
|
||||
return cls(self.subdomain, self.domain, self.username, self.secret_key, self.master_password, self.service_account_token, self.account_id)
|
||||
except TypeError as e:
|
||||
raise AnsibleLookupError(e)
|
||||
|
||||
|
@ -642,8 +676,9 @@ class LookupModule(LookupBase):
|
|||
secret_key = self.get_option("secret_key")
|
||||
master_password = self.get_option("master_password")
|
||||
service_account_token = self.get_option("service_account_token")
|
||||
account_id = self.get_option("account_id")
|
||||
|
||||
op = OnePass(subdomain, domain, username, secret_key, master_password, service_account_token)
|
||||
op = OnePass(subdomain, domain, username, secret_key, master_password, service_account_token, account_id)
|
||||
op.assert_logged_in()
|
||||
|
||||
values = []
|
||||
|
|
|
@ -35,6 +35,10 @@ DOCUMENTATION = '''
|
|||
version_added: 6.0.0
|
||||
default: '1password.com'
|
||||
type: str
|
||||
account_id:
|
||||
description: The account ID to target.
|
||||
type: str
|
||||
version_added: 7.5.0
|
||||
username:
|
||||
description: The username used to sign in.
|
||||
secret_key:
|
||||
|
@ -52,6 +56,7 @@ DOCUMENTATION = '''
|
|||
performed an initial sign in (meaning C(~/.op/config exists)), then only the O(master_password) is required.
|
||||
You may optionally specify O(subdomain) in this scenario, otherwise the last used subdomain will be used by C(op).
|
||||
- This lookup can perform an initial login by providing O(subdomain), O(username), O(secret_key), and O(master_password).
|
||||
- Can target a specific account by providing the O(account_id).
|
||||
- Due to the B(very) sensitive nature of these credentials, it is B(highly) recommended that you only pass in the minimal credentials
|
||||
needed at any given time. Also, store these credentials in an Ansible Vault using a key that is equal to or greater in strength
|
||||
to the 1Password master password.
|
||||
|
@ -96,8 +101,9 @@ class LookupModule(LookupBase):
|
|||
secret_key = self.get_option("secret_key")
|
||||
master_password = self.get_option("master_password")
|
||||
service_account_token = self.get_option("service_account_token")
|
||||
account_id = self.get_option("account_id")
|
||||
|
||||
op = OnePass(subdomain, domain, username, secret_key, master_password, service_account_token)
|
||||
op = OnePass(subdomain, domain, username, secret_key, master_password, service_account_token, account_id)
|
||||
op.assert_logged_in()
|
||||
|
||||
values = []
|
||||
|
|
Loading…
Reference in a new issue