Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
68cb197
Merge pull request #32 from Mahesh-Binayak/develop2
Mahesh-Binayak Mar 25, 2025
b246026
[MOSIP-41596]Updated the code to check for all partners.
Mahesh-Binayak May 30, 2025
28ecd39
Merge branch 'develop2' of https://github.com/mahesh-binayak/security…
May 30, 2025
e2c165d
Merge pull request #34 from Mahesh-Binayak/develop2
Mahesh-Binayak Jun 2, 2025
9bf0eff
[MOSIP-41897]adding dummy sonar code for pr check.
Mahesh-Binayak Jul 16, 2025
6df2c0d
[MOSIP-32607]Update bootstrap.properties
Mahesh-Binayak Jul 21, 2025
06a3a2e
Merge pull request #36 from Mahesh-Binayak/develop2
ckm007 Jul 22, 2025
68ae63c
[MOSIP-32607] updated helm charts
web-flow Jul 22, 2025
0e88b80
[MOSIP-32607] updated helm charts
Rakshithb1 Jul 23, 2025
b54fda5
[MOSIP-32607] updated added cluster role
Rakshithb1 Jul 23, 2025
de11ce8
[MOSIP-32607] updated added cluster role
Rakshithb1 Jul 23, 2025
17d35f0
[MOSIP-32607] updated added cluster role
Rakshithb1 Jul 23, 2025
3788a50
Merge pull request #37 from Rakshithb1/MOSIP-32607
ckm007 Jul 23, 2025
d6d81a6
[MOSIP-32607] updated host
Rakshithb1 Jul 23, 2025
de426b8
Merge pull request #38 from Rakshithb1/MOSIP-32607
ckm007 Jul 24, 2025
6084c63
[MOSIP-32607]
Rakshithb1 Jul 28, 2025
fc25dbc
Merge pull request #40 from Rakshithb1/MOSIP-32607
Mahesh-Binayak Jul 28, 2025
6637977
[MOSIP-32607] corrected helm path
Rakshithb1 Jul 28, 2025
bb11230
Merge pull request #41 from Rakshithb1/MOSIP-32607
Mahesh-Binayak Jul 28, 2025
f91d4c2
[MOSIP-32607]
Rakshithb1 Jul 28, 2025
d13e79e
Merge pull request #42 from Rakshithb1/MOSIP-32607
Mahesh-Binayak Jul 28, 2025
93e8bb5
[MOSIP-32607] added values.yaml in install.sh
Rakshithb1 Jul 28, 2025
d89f95d
Merge pull request #44 from Rakshithb1/MOSIP-32607
Mahesh-Binayak Jul 29, 2025
6e3bee9
[MOSIP-32607] updated values.yaml
Rakshithb1 Jul 30, 2025
18d8215
[MOSIP-32607] updated values.yaml
Rakshithb1 Jul 30, 2025
d573a26
Merge pull request #45 from Rakshithb1/MOSIP-32607
Mahesh-Binayak Jul 30, 2025
8685b38
[MOSIP-32607]
Rakshithb1 Aug 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/chart-lint-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ on:
- MOSIP*
- release*
paths:
- './helm/**'
- 'helm/**'

jobs:
chart-lint-publish:
Expand Down
7 changes: 7 additions & 0 deletions certmanager/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ ARG container_user_group=mosip
ARG container_user_uid=1001
ARG container_user_gid=1001

# Install kubectl binary
RUN apt-get -y update \
&& apt-get install -y curl \
&& curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" \
&& chmod +x ./kubectl && mv ./kubectl /usr/local/bin/kubectl

# Create user group
RUN groupadd -r ${container_user_group} && useradd -u ${container_user_uid} -r -g ${container_user_group} -s /bin/bash -m -d /home/${container_user} ${container_user}
RUN chown -R ${container_user}:${container_user} /home/${container_user}
Expand All @@ -30,6 +36,7 @@ ENV db-server=
ENV db-port=
ENV db-su-user=
ENV postgres-password=
ENV ns_esignet=esignet

COPY partner.properties .
COPY requirements.txt .
Expand Down
11 changes: 6 additions & 5 deletions certmanager/bootstrap.properties
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
[Database]
db-host = postgres.qa-platform1.mosip.net
db-host = postgres.sandbox.mosip.net
db-port = 5432
db-su-user = postgres
postgres-password = z63RJy8Ldt
postgres-password = HEdMa9Z****Tu**
[API]
mosip-api-internal-host=api-internal.qa-platform1.mosip.net
mosip_pms_client_secret=ZapZsW5X8AtrkSai
pre-expiry-days=400
mosip-api-internal-host=api-internal.sandbox.mosip.net
mosip_deployment_client_secret=w9xp2****Q4N1709B
pre-expiry-days=40
mosip-api-external-host=api.sandbox.mosip.net
157 changes: 132 additions & 25 deletions certmanager/checkupdate.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
import json
import psycopg2
import requests
import subprocess
from urllib.request import Request, urlopen
from urllib.error import HTTPError
from datetime import datetime, timedelta
from datetime import datetime, timedelta, timezone
from configparser import ConfigParser

# Function to read value from bootstrap.properties
Expand Down Expand Up @@ -69,6 +70,10 @@ def retrieve_certificate_data(partner_id, db_host, db_port, db_user, db_password
print(f"Error retrieving certificate data for Partner ID '{partner_id}': {str(e)}")
return None

# Function to get current UTC time in ISO 8601 format with milliseconds
def get_utc_timestamp():
return datetime.utcnow().replace(tzinfo=timezone.utc).isoformat(timespec='milliseconds').replace('+00:00', 'Z')

# Function to authenticate and retrieve the token
def authenticate_and_get_token(base_url, client_secret):
auth_url = f"https://{base_url}/v1/authmanager/authenticate/clientidsecretkey"
Expand All @@ -78,75 +83,139 @@ def authenticate_and_get_token(base_url, client_secret):
"metadata": {},
"request": {
"appId": "ida",
"clientId": "mosip-pms-client",
"clientId": "mosip-deployment-client",
"secretKey": client_secret
},
"requesttime": "",
"requesttime": get_utc_timestamp(),
"version": "string"
}
response = requests.post(auth_url, headers=headers, json=auth_data)
if response.status_code == 200:
return response.headers.get("authorization")
print("Authentication failed.", response.text)
print("Authentication failed.")
return None

# Function to upload certificate
# Returns signedCertificateData if successful
def upload_certificate_with_token(token, cert_data, partner_id, base_url):
upload_url = f"https://{base_url}/v1/partnermanager/partners/certificate/upload"
headers = {"Content-Type": "application/json", "Cookie": f"Authorization={token}"}
partner_domain = "MISP" if partner_id == "mpartner-default-esignet" else "AUTH"
upload_data = {
"id": "string",
"metadata": {},
"request": {
"certificateData": cert_data.replace("\\n", "\n"),
"partnerDomain": "AUTH",
"partnerDomain": partner_domain,
"partnerId": partner_id
},
"requesttime": "",
"requesttime": get_utc_timestamp(),
"version": "string"
}
response = requests.post(upload_url, headers=headers, json=upload_data)
if "certificateId" not in response.text:
print("Certificate renewal failed.", response.text)
print(f"[{partner_id}] Certificate renewal failed.")
return None
return json.loads(response.text)['response']['signedCertificateData']

# Function to post-upload to dependent systems
def post_upload_to_system(endpoint, token, app_id, cert_data, reference_id, bearer=False):
if bearer:
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {token}"
}
else:
print("Certificate renewed successfully.")
headers = {
"Content-Type": "application/json",
"Cookie": f"Authorization={token}"
}

payload = {
"request": {
"certificateData": cert_data,
"applicationId": app_id,
"referenceId": reference_id
},
"requestTime": get_utc_timestamp()
}

# Fetching environment variables or values from bootstrap.properties
response = requests.post(endpoint, headers=headers, json=payload)

if response.status_code == 200 and 'Upload Success' in response.text:
print(f"[{partner_id}] certificate uploaded back to [{app_id}] successfully.")
return True
else:
print(f"[{partner_id}] certificate upload back to [{app_id}] failed.")
return False

# Load configuration
postgres_host = os.environ.get('db-host') or read_bootstrap_properties('db-host')
postgres_port = os.environ.get('db-port') or read_bootstrap_properties('db-port')
postgres_user = os.environ.get('db-su-user') or read_bootstrap_properties('db-su-user')
postgres_password = os.environ.get('postgres-password') or read_bootstrap_properties('postgres-password')
base_url = os.environ.get('mosip-api-internal-host') or read_bootstrap_properties('mosip-api-internal-host')
client_secret = os.environ.get('mosip_pms_client_secret') or read_bootstrap_properties('mosip_pms_client_secret')
pre_expiry_days = os.environ.get('pre-expiry-days') or read_bootstrap_properties('pre-expiry-days')
base_esignet_url = os.environ.get('mosip-api-host') or read_bootstrap_properties('mosip-api-external-host')
client_secret = os.environ.get('mosip_deployment_client_secret') or read_bootstrap_properties('mosip_deployment_client_secret')
pre_expiry_days = int(os.environ.get('pre-expiry-days') or read_bootstrap_properties('pre-expiry-days'))
ns_esignet = os.environ.get('ns_esignet')
TOKEN = authenticate_and_get_token(base_url, client_secret)

if TOKEN:
partner_ids = os.environ.get('PARTNER_IDS_ENV')
if partner_ids:
partner_ids = partner_ids.split(',')
print ("Getting list of partners from env variable")
print("Getting list of partners from env variable")
else:
with open('partner.properties', 'r') as file:
for line in file:
if line.startswith('PARTNER_ID'):
partner_ids = line.strip().split('=')[1].split(',')
print ("Getting list of partners from local variable")
print("Getting list of partners from local variable")

for PARTNER_ID in partner_ids:
print(f"\nProcessing partner ID: {PARTNER_ID.strip()}")
PARTNER_ID = PARTNER_ID.strip()
print(f"\nProcessing partner ID: {PARTNER_ID}")
try:
req = Request(f"https://{base_url}/v1/partnermanager/partners/{PARTNER_ID.strip()}/certificate",
headers={"Content-Type": "application/json", "Cookie": f"Authorization={TOKEN}"},
method="GET")
req = Request(
f"https://{base_url}/v1/partnermanager/partners/{PARTNER_ID}/certificate",
headers={"Content-Type": "application/json", "Cookie": f"Authorization={TOKEN}"},
method="GET"
)
response = urlopen(req)
response_data = json.loads(response.read().decode('utf-8'))
CERTIFICATE_DATA = response_data.get('response', {}).get('certificateData')
raw_data = response.read().decode('utf-8')
try:
response_data = json.loads(raw_data)
except json.JSONDecodeError:
print(f"[{PARTNER_ID}] Invalid JSON response.")
continue

if not response_data or not isinstance(response_data, dict):
print(f"[{PARTNER_ID}] Invalid or empty response.")
continue

cert_info = response_data.get('response')
CERTIFICATE_DATA = cert_info.get('certificateData') if cert_info else None

if not CERTIFICATE_DATA:
print(f"[{PARTNER_ID}] Certificate data not found.")
continue

expiration_date = os.popen(f"echo '{CERTIFICATE_DATA}' | openssl x509 -noout -enddate").read().split('=')[1].strip()
if is_certificate_expired(expiration_date) or (datetime.strptime(expiration_date, "%b %d %H:%M:%S %Y %Z") - datetime.utcnow()) <= timedelta(days=int(pre_expiry_days)):
write_to_expired_txt(PARTNER_ID.strip())
expiry_dt = datetime.strptime(expiration_date, "%b %d %H:%M:%S %Y %Z")
days_left = (expiry_dt - datetime.utcnow()).days

if is_certificate_expired(expiration_date) or days_left <= int(pre_expiry_days):
print(f"[{PARTNER_ID}] Certificate is expired or will expire in {days_left} day(s). Renewing...")
write_to_expired_txt(PARTNER_ID)
else:
print(f"[{PARTNER_ID}] Certificate is valid. {days_left} day(s) left.")

except HTTPError as e:
print(f"Error fetching certificate for {PARTNER_ID}: {e}")
print(f"[{PARTNER_ID}] HTTP error while fetching certificate: {e}")
continue
except Exception as e:
print(f"[{PARTNER_ID}] Unexpected error: {e}")
continue

if os.path.exists("expired.txt"):
Expand All @@ -157,8 +226,46 @@ def upload_certificate_with_token(token, cert_data, partner_id, base_url):

for partner_id in expired_partner_ids:
cert_data = retrieve_certificate_data(partner_id, postgres_host, postgres_port, postgres_user, postgres_password)
if cert_data:
upload_certificate_with_token(TOKEN, cert_data, partner_id, base_url)
print("Certificate check and renewal process completed.")
if not cert_data:
continue

try:
pem = cert_data.replace("\\n", "\n")
end_date_str = os.popen(f"echo '{pem}' | openssl x509 -noout -enddate").read().split('=')[1].strip()
end_date = datetime.strptime(end_date_str, "%b %d %H:%M:%S %Y %Z")
if (end_date - datetime.utcnow()).days < 365:
print(f"DB cert for {partner_id} has less than 365 days left. Skipping.")
continue
except Exception as e:
print(f"Error validating DB cert for {partner_id}: {e}")
continue

signed_cert = upload_certificate_with_token(TOKEN, cert_data, partner_id, base_url)
if not signed_cert:
continue

# Post-upload to relevant systems
success = True
if partner_id == 'mpartner-default-esignet':
success = post_upload_to_system(f"https://{base_esignet_url}/v1/esignet/system-info/uploadCertificate", TOKEN, "OIDC_PARTNER", signed_cert, "", bearer=True)
if success:
if ns_esignet:
subprocess.run(["kubectl", "rollout", "restart", "deployment", "esignet", "-n", ns_esignet], check=True)
else:
print("Environment variable 'ns_esignet' not set. Cannot restart esignet deployment.")
else:
print(f"[{partner_id}] Upload to Esignet failed. Skipping restart.")
elif partner_id == 'mpartner-default-digitalcard':
success = post_upload_to_system(f"https://{base_url}/v1/keymanager/uploadCertificate", TOKEN, "DIGITAL_CARD", signed_cert, partner_id)
elif partner_id == 'mpartner-default-auth':
success = post_upload_to_system(f"https://{base_url}/idauthentication/v1/internal/uploadCertificate", TOKEN, "IDA", signed_cert, partner_id)
elif partner_id == 'mpartner-default-resident':
success = post_upload_to_system(f"https://{base_url}/v1/keymanager/uploadCertificate", TOKEN, "RESIDENT", signed_cert, partner_id)

if success or partner_id not in [
'mpartner-default-esignet', 'mpartner-default-digitalcard', 'mpartner-default-auth', 'mpartner-default-resident']:
print(f"[{partner_id}] certificate renewed successfully and will be valid for 1 more year.")

print("MOSIP Certificate Manager Run Completed.")
else:
print("Failed to get auth-token")
2 changes: 1 addition & 1 deletion certmanager/partner.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
PARTNER_ID=mpartner-default-abis
PARTNER_ID=mpartner-default-resident,mpartner-default-abis
7 changes: 4 additions & 3 deletions deploy/mosipcertmanager/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# mosipcertmanager
Helm chart for installing mosipcertmanager

## Introduction
It's a cronjob that checks DBs for partner certificate expiry dates and renews the certificates if expired.
## Introduction
It's a cronjob that checks partner certificate expiry dates and renews the certificates if expired.

## Install
RUN Install script
* Review the `values.yaml` file and ensure that the database parameter values and partner IDs are set according to your environment
* RUN Install script
```
./install.sh
```
Expand Down
2 changes: 1 addition & 1 deletion deploy/mosipcertmanager/copy_cm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# DST_NS: Destination (current) namespace

function copying_cm() {
UTIL_URL=https:https://raw.githubusercontent.com/mosip/mosip-infra/master/deployment/v3/utils/copy_cm_func.sh
UTIL_URL=https://raw.githubusercontent.com/mosip/mosip-infra/master/deployment/v3/utils/copy_cm_func.sh
COPY_UTIL=./copy_cm_func.sh

wget -q $UTIL_URL -O copy_cm_func.sh && chmod +x copy_cm_func.sh
Expand Down
3 changes: 1 addition & 2 deletions deploy/mosipcertmanager/copy_secrets.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@
# DST_NS: Destination namespace

function copying_secrets() {
UTIL_URL=https:https://raw.githubusercontent.com/mosip/mosip-infra/master/deployment/v3/utils/copy_cm_func.sh
UTIL_URL=https://raw.githubusercontent.com/mosip/mosip-infra/master/deployment/v3/utils/copy_cm_func.sh
COPY_UTIL=./copy_cm_func.sh

wget -q $UTIL_URL -O copy_cm_func.sh && chmod +x copy_cm_func.sh

DST_NS=mosipcertmanager
$COPY_UTIL secret s3 s3 $DST_NS
$COPY_UTIL secret postgres-postgresql postgres $DST_NS
$COPY_UTIL secret keycloak-client-secrets keycloak $DST_NS
return 0
Expand Down
2 changes: 1 addition & 1 deletion deploy/mosipcertmanager/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ function installing_mosipcertmanager() {
./copy_secrets.sh

echo Installing mosipcertmanager
helm -n $NS install mosipcertmanager mosip/mosipcertmanager --wait --version $CHART_VERSION
helm -n $NS install mosipcertmanager mosip/mosipcertmanager -f values.yaml --wait --version $CHART_VERSION
return 0
}

Expand Down
14 changes: 14 additions & 0 deletions deploy/mosipcertmanager/values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

crontime: "0 3 * * *" ## run cronjob every day at 3 AM (time hr: 0-23 )

mosipcertmanager:
configmaps:
db:
db-port: '5432'
db-su-user: 'postgres'
db-host: 'postgres.sandbox.mosip.net'
partner-ids-env:
PARTNER_IDS_ENV: mpartner-default-print,mpartner-default-abis,mpartner-default-mobile,mpartner-default-digitalcard,mpartner-default-auth,mpartner-default-resident,mpartner-default-demo-oidc,mpartner-default-resident-oidc,mpartner-default-mimotooidc,mpartner-default-esignet,mpartner-default-mimotokeybinding
mosipcertmanager:
pre-expiry-days: '40'

8 changes: 8 additions & 0 deletions helm/mosipcertmanager/templates/clusterrole.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ .Release.Name }}-deployment-clusterrole
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "patch", "list", "watch"]
12 changes: 12 additions & 0 deletions helm/mosipcertmanager/templates/clusterrolebinding.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ .Release.Name }}-deployment-clusterrolebinding
subjects:
- kind: ServiceAccount
name: {{ template "mosipcertmanager.serviceAccountName" . }}
namespace: {{ .Release.Namespace }}
roleRef:
kind: ClusterRole
name: {{ .Release.Name }}-deployment-clusterrole
apiGroup: rbac.authorization.k8s.io
Loading