mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
[PR #7308/35b252c9 backport][stable-7] allow specifying a 1Password account ID (#7328)
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>
(cherry picked from commit 35b252c9ad
)
Co-authored-by: Ilya Trushchenko <i@whitehat.com.ua>
This commit is contained in:
parent
b862c0db49
commit
1a0c9eb5e6
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
|
type: str
|
||||||
subdomain:
|
subdomain:
|
||||||
description: The 1Password subdomain to authenticate against.
|
description: The 1Password subdomain to authenticate against.
|
||||||
|
account_id:
|
||||||
|
description: The account ID to target.
|
||||||
|
type: str
|
||||||
|
version_added: 7.5.0
|
||||||
username:
|
username:
|
||||||
description: The username used to sign in.
|
description: The username used to sign in.
|
||||||
secret_key:
|
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
|
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).
|
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).
|
- 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
|
- 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
|
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.
|
to the 1Password master password.
|
||||||
|
@ -93,6 +98,12 @@ EXAMPLES = """
|
||||||
master_password=vault_master_password,
|
master_password=vault_master_password,
|
||||||
username='tweety@acme.com',
|
username='tweety@acme.com',
|
||||||
secret_key=vault_secret_key)
|
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 = """
|
RETURN = """
|
||||||
|
@ -119,13 +130,23 @@ from ansible_collections.community.general.plugins.module_utils.onepassword impo
|
||||||
class OnePassCLIBase(with_metaclass(abc.ABCMeta, object)):
|
class OnePassCLIBase(with_metaclass(abc.ABCMeta, object)):
|
||||||
bin = "op"
|
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.subdomain = subdomain
|
||||||
self.domain = domain
|
self.domain = domain
|
||||||
self.username = username
|
self.username = username
|
||||||
self.master_password = master_password
|
self.master_password = master_password
|
||||||
self.secret_key = secret_key
|
self.secret_key = secret_key
|
||||||
self.service_account_token = service_account_token
|
self.service_account_token = service_account_token
|
||||||
|
self.account_id = account_id
|
||||||
|
|
||||||
self._path = None
|
self._path = None
|
||||||
self._version = None
|
self._version = None
|
||||||
|
@ -293,7 +314,9 @@ class OnePassCLIv1(OnePassCLIBase):
|
||||||
|
|
||||||
def assert_logged_in(self):
|
def assert_logged_in(self):
|
||||||
args = ["get", "account"]
|
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)
|
account = "{subdomain}.{domain}".format(subdomain=self.subdomain, domain=self.domain)
|
||||||
args.extend(["--account", account])
|
args.extend(["--account", account])
|
||||||
|
|
||||||
|
@ -326,6 +349,10 @@ class OnePassCLIv1(OnePassCLIBase):
|
||||||
|
|
||||||
def get_raw(self, item_id, vault=None, token=None):
|
def get_raw(self, item_id, vault=None, token=None):
|
||||||
args = ["get", "item", item_id]
|
args = ["get", "item", item_id]
|
||||||
|
|
||||||
|
if self.account_id:
|
||||||
|
args.extend(["--account", self.account_id])
|
||||||
|
|
||||||
if vault is not None:
|
if vault is not None:
|
||||||
args += ["--vault={0}".format(vault)]
|
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
|
# an interactive prompt. Only run 'op account get' after first listing accounts to see
|
||||||
# if there are any previously configured accounts.
|
# if there are any previously configured accounts.
|
||||||
args = ["account", "get"]
|
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)
|
account = "{subdomain}.{domain}".format(subdomain=self.subdomain, domain=self.domain)
|
||||||
args.extend(["--account", account])
|
args.extend(["--account", account])
|
||||||
|
|
||||||
|
@ -533,6 +562,10 @@ class OnePassCLIv2(OnePassCLIBase):
|
||||||
|
|
||||||
def get_raw(self, item_id, vault=None, token=None):
|
def get_raw(self, item_id, vault=None, token=None):
|
||||||
args = ["item", "get", item_id, "--format", "json"]
|
args = ["item", "get", item_id, "--format", "json"]
|
||||||
|
|
||||||
|
if self.account_id:
|
||||||
|
args.extend(["--account", self.account_id])
|
||||||
|
|
||||||
if vault is not None:
|
if vault is not None:
|
||||||
args += ["--vault={0}".format(vault)]
|
args += ["--vault={0}".format(vault)]
|
||||||
|
|
||||||
|
@ -559,13 +592,14 @@ class OnePassCLIv2(OnePassCLIBase):
|
||||||
|
|
||||||
class OnePass(object):
|
class OnePass(object):
|
||||||
def __init__(self, subdomain=None, domain="1password.com", username=None, secret_key=None, master_password=None,
|
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.subdomain = subdomain
|
||||||
self.domain = domain
|
self.domain = domain
|
||||||
self.username = username
|
self.username = username
|
||||||
self.secret_key = secret_key
|
self.secret_key = secret_key
|
||||||
self.master_password = master_password
|
self.master_password = master_password
|
||||||
self.service_account_token = service_account_token
|
self.service_account_token = service_account_token
|
||||||
|
self.account_id = account_id
|
||||||
|
|
||||||
self.logged_in = False
|
self.logged_in = False
|
||||||
self.token = None
|
self.token = None
|
||||||
|
@ -578,7 +612,7 @@ class OnePass(object):
|
||||||
for cls in OnePassCLIBase.__subclasses__():
|
for cls in OnePassCLIBase.__subclasses__():
|
||||||
if cls.supports_version == version.split(".")[0]:
|
if cls.supports_version == version.split(".")[0]:
|
||||||
try:
|
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:
|
except TypeError as e:
|
||||||
raise AnsibleLookupError(e)
|
raise AnsibleLookupError(e)
|
||||||
|
|
||||||
|
@ -642,8 +676,9 @@ class LookupModule(LookupBase):
|
||||||
secret_key = self.get_option("secret_key")
|
secret_key = self.get_option("secret_key")
|
||||||
master_password = self.get_option("master_password")
|
master_password = self.get_option("master_password")
|
||||||
service_account_token = self.get_option("service_account_token")
|
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()
|
op.assert_logged_in()
|
||||||
|
|
||||||
values = []
|
values = []
|
||||||
|
|
|
@ -35,6 +35,10 @@ DOCUMENTATION = '''
|
||||||
version_added: 6.0.0
|
version_added: 6.0.0
|
||||||
default: '1password.com'
|
default: '1password.com'
|
||||||
type: str
|
type: str
|
||||||
|
account_id:
|
||||||
|
description: The account ID to target.
|
||||||
|
type: str
|
||||||
|
version_added: 7.5.0
|
||||||
username:
|
username:
|
||||||
description: The username used to sign in.
|
description: The username used to sign in.
|
||||||
secret_key:
|
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.
|
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).
|
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).
|
- 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
|
- 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
|
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.
|
to the 1Password master password.
|
||||||
|
@ -96,8 +101,9 @@ class LookupModule(LookupBase):
|
||||||
secret_key = self.get_option("secret_key")
|
secret_key = self.get_option("secret_key")
|
||||||
master_password = self.get_option("master_password")
|
master_password = self.get_option("master_password")
|
||||||
service_account_token = self.get_option("service_account_token")
|
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()
|
op.assert_logged_in()
|
||||||
|
|
||||||
values = []
|
values = []
|
||||||
|
|
Loading…
Reference in a new issue