Skip to content

Commit 2b0513b

Browse files
committed
PackageCRC: add back user_pass, mutual_tls & identity auth methods
expose through METRICS_UTILITY_SHIP_AUTH should still remove these if unused after metrics-service CRC uploads
1 parent 2de2c7f commit 2b0513b

File tree

1 file changed

+112
-37
lines changed

1 file changed

+112
-37
lines changed

metrics_utility/automation_controller_billing/package/package_crc.py

Lines changed: 112 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import base64
12
import json
23
import os
34

@@ -8,7 +9,7 @@
89

910
import metrics_utility.base as base
1011

11-
from metrics_utility.exceptions import FailedToUploadPayload
12+
from metrics_utility.exceptions import FailedToUploadPayload, MetricsException
1213
from metrics_utility.logger import logger
1314

1415

@@ -38,6 +39,11 @@ def _get_rh_password(self):
3839
def _get_http_request_headers(self):
3940
return get_awx_http_client_headers()
4041

42+
# only service_account was reachable in 0.6.0 without changing code; identity still isn't
43+
# FIXME: only use for service if needed, remove if not
44+
def _shipping_auth(self):
45+
return os.getenv('METRICS_UTILITY_SHIP_AUTH', 'service_account') # identity | mutual_tls | service_account | user_pass
46+
4147
def is_shipping_configured(self):
4248
if not self.tar_path:
4349
logger.error('Insights for Ansible Automation Platform TAR not found')
@@ -54,17 +60,19 @@ def is_shipping_configured(self):
5460
logger.error('METRICS_UTILITY_CRC_INGRESS_URL is not set')
5561
return False
5662

57-
if not self._get_sso_url():
58-
logger.error('METRICS_UTILITY_CRC_SSO_URL is not set')
59-
return False
63+
if self._shipping_auth() == 'service_account':
64+
if not self._get_sso_url():
65+
logger.error('METRICS_UTILITY_CRC_SSO_URL is not set')
66+
return False
6067

61-
if not self._get_rh_user():
62-
logger.error('METRICS_UTILITY_SERVICE_ACCOUNT_ID is not set')
63-
return False
68+
if self._shipping_auth() in ('service_account', 'user_pass'):
69+
if not self._get_rh_user():
70+
logger.error('METRICS_UTILITY_SERVICE_ACCOUNT_ID is not set')
71+
return False
6472

65-
if not self._get_rh_password():
66-
logger.error('METRICS_UTILITY_SERVICE_ACCOUNT_SECRET is not set')
67-
return False
73+
if not self._get_rh_password():
74+
logger.error('METRICS_UTILITY_SERVICE_ACCOUNT_SECRET is not set')
75+
return False
6876

6977
# _get_proxy_url is optional
7078

@@ -89,43 +97,110 @@ def ship(self):
8997
)
9098
}
9199

92-
s = requests.Session()
93-
s.headers = self._get_http_request_headers()
94-
s.headers.pop('Content-Type')
100+
response = self._request(files)
101+
102+
# Accept 2XX status_codes
103+
if response.status_code >= 300:
104+
raise FailedToUploadPayload(f'Upload failed with status {response.status_code}, {response.text}')
105+
106+
self.shipping_successful = True
107+
return True
108+
109+
def _session(self):
110+
session = requests.Session()
111+
session.headers = self._get_http_request_headers()
112+
session.headers.pop('Content-Type')
113+
114+
session.verify = self.CERT_PATH
115+
session.timeout = (31, 31)
95116

96-
url = self._get_ingress_url()
97-
self.shipping_successful = self._send_data(url, files, s)
117+
return session
98118

99-
return self.shipping_successful
119+
def _bearer(self):
120+
response = requests.post(
121+
self._get_sso_url(),
122+
data={'client_id': self._get_rh_user(), 'client_secret': self._get_rh_password(), 'grant_type': 'client_credentials'},
123+
headers={'Content-Type': 'application/x-www-form-urlencoded'},
124+
timeout=(31, 31),
125+
verify=self.CERT_PATH,
126+
)
100127

101-
def _send_data(self, url, files, session):
102-
sso_url = self._get_sso_url()
103-
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
128+
return json.loads(response.content)['access_token']
104129

105-
data = {'client_id': self._get_rh_user(), 'client_secret': self._get_rh_password(), 'grant_type': 'client_credentials'}
130+
def _proxies(self):
131+
if not self._get_proxy_url():
132+
return {}
106133

107-
r = requests.post(sso_url, headers=headers, data=data, verify=self.CERT_PATH, timeout=(31, 31))
108-
access_token = json.loads(r.content)['access_token']
134+
return {'https': self._get_proxy_url()}
109135

110-
# Query crc with bearer token
111-
headers = session.headers
112-
headers['authorization'] = f'Bearer {access_token}'
136+
def _identity(self, url, files):
137+
session = self._session()
113138

114-
proxies = {}
115-
if self._get_proxy_url():
116-
proxies = {'https': self._get_proxy_url()}
139+
# FIXME: make parametrizable, if used
140+
identity = {
141+
'identity': {
142+
'type': 'User',
143+
'account_number': '0000001',
144+
'user': {'is_org_admin': True},
145+
'internal': {'org_id': '000001'},
146+
}
147+
}
148+
session.headers['x-rh-identity'] = base64.b64encode(json.dumps(identity).encode('utf8'))
117149

118-
response = session.post(
150+
return session.post(
119151
url,
120152
files=files,
121-
verify=self.CERT_PATH,
122-
proxies=proxies,
123-
headers=headers,
124-
timeout=(31, 31),
153+
proxies=self._proxies(),
125154
)
126155

127-
# Accept 2XX status_codes
128-
if response.status_code >= 300:
129-
raise FailedToUploadPayload(f'Upload failed with status {response.status_code}, {response.text}')
156+
def _mutual_tls(self, url, files):
157+
session = self._session()
130158

131-
return True
159+
# a single file (containing the private key and the certificate)
160+
# or a tuple of both files paths (cert_file, keyfile)
161+
session.cert = (
162+
'/etc/pki/consumer/cert.pem',
163+
'/etc/pki/consumer/key.pem',
164+
)
165+
166+
return session.post(
167+
url,
168+
files=files,
169+
proxies=self._proxies(),
170+
)
171+
172+
def _service_account(self, url, files):
173+
session = self._session()
174+
175+
access_token = self._bearer()
176+
session.headers['authorization'] = f'Bearer {access_token}'
177+
178+
return session.post(
179+
url,
180+
files=files,
181+
proxies=self._proxies(),
182+
)
183+
184+
def _user_pass(self, url, files):
185+
session = self._session()
186+
session.auth = (self._get_rh_user(), self._get_rh_password())
187+
188+
return session.post(
189+
url,
190+
files=files,
191+
proxies=self._proxies(),
192+
)
193+
194+
def _request(self, url, files):
195+
url = self._get_ingress_url()
196+
mode = self._shipping_auth()
197+
if mode == 'identity':
198+
return self._identity(url, files)
199+
elif mode == 'mutual_tls':
200+
return self._mutual_tls(url, files)
201+
elif mode == 'service_account':
202+
return self._service_account(url, files)
203+
elif mode == 'user_pass':
204+
return self._user_pass(url, files)
205+
else:
206+
raise MetricsException(f'Invalid METRICS_UTILITY_SHIP_AUTH {mode}: identity | mutual_tls | service_account (default) | user_pass')

0 commit comments

Comments
 (0)