Skip to content

Commit

Permalink
Merge pull request #930 from intuitem/improve/clica-docker
Browse files Browse the repository at this point in the history
  • Loading branch information
ab-smith authored Oct 13, 2024
2 parents 19bf6f4 + 130e667 commit 4eb2085
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 34 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ To interact with it:

## Setting CISO Assistant for production

The docker-compose.yml highlights a relevant configuration with a Caddy proxy in front of the frontend.
The docker-compose-prod.yml highlights a relevant configuration with a Caddy proxy in front of the frontend. It exposes API calls only for SSO. Note that docker-compose.yml exposes the full API, which is not yet recommended for production.

Set DJANGO_DEBUG=False for security reason.

Expand Down
78 changes: 48 additions & 30 deletions cli/clica.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ def cli():
def init_config():
"""Create/Reset the config file."""
template_data = {
"rest": {"url": "http://localhost:8000/api"},
"rest": {
"url": "https://localhost:8443/api",
"verify_certificate": True,
},
"credentials": {"email": "[email protected]", "password": ""},
}
if click.confirm(
Expand All @@ -50,15 +53,17 @@ def init_config():
cli_cfg = yaml.safe_load(yfile)
except FileNotFoundError:
print(
"Config file not found. Running the init command to create it but you need to fill it."
"Config file not found. Running the init command to create it but you need to fill it.",
file=sys.stderr,
)
init_config()

try:
API_URL = cli_cfg["rest"]["url"]
except KeyError:
print(
"Missing API URL. Check that the config.yaml file is properly set or trigger init command to create a new one."
"Missing API URL. Check that the config.yaml file is properly set or trigger init command to create a new one.",
file=sys.stderr,
)
sys.exit(1)

Expand All @@ -67,18 +72,21 @@ def init_config():
PASSWORD = cli_cfg["credentials"]["password"]
except KeyError:
print(
"Missing credentials in the config file. You need to pass them to the CLI in this case."
"Missing credentials in the config file. You need to pass them to the CLI in this case.",
file=sys.stderr,
)

VERIFY_CERTIFICATE = cli_cfg["rest"].get("verify_certificate", True)


def check_auth():
if Path(".tmp.yaml").exists():
click.echo("Found auth data. Trying them")
click.echo("Found auth data. Trying them", err=True)
with open(".tmp.yaml", "r") as yfile:
auth_data = yaml.safe_load(yfile)
return auth_data["token"]
else:
click.echo("Could not find authentication data.")
click.echo("Could not find authentication data.", err=True)


TOKEN = check_auth()
Expand All @@ -93,31 +101,32 @@ def auth(email, password):
if email and password:
data = {"username": email, "password": password}
else:
print("trying credentials from the config file")
print("trying credentials from the config file", file=sys.stderr)
if EMAIL and PASSWORD:
data = {"username": EMAIL, "password": PASSWORD}
else:
print("Could not find any usable credentials.")
print("Could not find any usable credentials.", file=sys.stderr)
sys.exit(1)
headers = {"accept": "application/json", "Content-Type": "application/json"}

res = requests.post(url, data, headers)
res = requests.post(url, data, headers, verify=VERIFY_CERTIFICATE)
print(res.status_code)
if res.status_code == 200:
with open(".tmp.yaml", "w") as yfile:
yaml.safe_dump(res.json(), yfile)
print("Looks good, you can move to other commands.")
print("Looks good, you can move to other commands.", file=sys.stderr)
else:
print(
"Check your credentials again. You can set them on the config file or on the command line."
"Check your credentials again. You can set them on the config file or on the command line.",
file=sys.stderr,
)
print(res.json())


def _get_folders():
url = f"{API_URL}/folders/"
headers = {"Authorization": f"Token {TOKEN}"}
res = requests.get(url, headers=headers)
res = requests.get(url, headers=headers, verify=VERIFY_CERTIFICATE)
if res.status_code == 200:
output = res.json()
for folder in output["results"]:
Expand Down Expand Up @@ -158,12 +167,14 @@ def import_assets(file):
"folder": GLOBAL_FOLDER_ID,
"type": asset_type,
}
res = requests.post(url, json=data, headers=headers)
res = requests.post(
url, json=data, headers=headers, verify=VERIFY_CERTIFICATE
)
if res.status_code != 201:
click.echo("❌ something went wrong")
click.echo("❌ something went wrong", err=True)
print(res.json())
else:
print(f"✅ {name} created")
print(f"✅ {name} created", file=sys.stderr)


@click.command()
Expand Down Expand Up @@ -192,20 +203,22 @@ def import_controls(file):
"csf_function": csf_function.lower(),
"category": category.lower(),
}
res = requests.post(url, json=data, headers=headers)
res = requests.post(
url, json=data, headers=headers, verify=VERIFY_CERTIFICATE
)
if res.status_code != 201:
click.echo("❌ something went wrong")
click.echo("❌ something went wrong", err=True)
print(res.json())
else:
print(f"✅ {name} created")
print(f"✅ {name} created", file=sys.stderr)


@click.command()
@click.option(
"--file", required=True, help="Path of the csv file with the list of evidences"
)
def evidences_templates(file):
"""Create evidences templates. Check the samples for format."""
def import_evidences(file):
"""Import evidences. Check the samples for format."""
df = pd.read_csv(file)
GLOBAL_FOLDER_ID, _ = _get_folders()

Expand All @@ -222,33 +235,38 @@ def evidences_templates(file):
"applied_controls": [],
"requirement_assessments": [],
}
res = requests.post(url, json=data, headers=headers)
res = requests.post(
url, json=data, headers=headers, verify=VERIFY_CERTIFICATE
)
if res.status_code != 201:
click.echo("❌ something went wrong")
click.echo("❌ something went wrong", err=True)
print(res.json())
else:
print(f"✅ {row['name']} created")
print(f"✅ {row['name']} created", file=sys.stderr)


@click.command()
@click.option("--file", required=True, help="Path to the attachment to upload")
@click.option("--name", required=True, help="Name of the evidence")
def upload_evidence(file, name):
def upload_attachment(file, name):
"""Upload attachment as evidence"""

headers = {
"Authorization": f"Token {TOKEN}",
}
# Get evidence ID by name
url = f"{API_URL}/evidences/"
res = requests.get(url, headers=headers, params={"name": name})
res = requests.get(
url, headers=headers, params={"name": name}, verify=VERIFY_CERTIFICATE
)
data = res.json()
print(data)
if res.status_code != 200:
print(data)
print(f"Error: check credentials or filename.")
print(f"Error: check credentials or filename.", file=sys.stderr)
return
if not data["results"]:
print(f"Error: No evidence found with name '{name}'")
print(f"Error: No evidence found with name '{name}'", file=sys.stderr)
return

evidence_id = data["results"][0]["id"]
Expand All @@ -261,7 +279,7 @@ def upload_evidence(file, name):
"Content-Disposition": f'attachment;filename="{filename}"',
}
with open(file, "rb") as f:
res = requests.post(url, headers=headers, data=f)
res = requests.post(url, headers=headers, data=f, verify=VERIFY_CERTIFICATE)
print(res)
print(res.text)

Expand All @@ -270,8 +288,8 @@ def upload_evidence(file, name):
cli.add_command(auth)
cli.add_command(import_assets)
cli.add_command(import_controls)
cli.add_command(evidences_templates)
cli.add_command(import_evidences)
cli.add_command(init_config)
cli.add_command(upload_evidence)
cli.add_command(upload_attachment)
if __name__ == "__main__":
cli()
44 changes: 44 additions & 0 deletions docker-compose-prod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
services:
backend:
container_name: backend
image: ghcr.io/intuitem/ciso-assistant-community/backend:latest
restart: always
environment:
- ALLOWED_HOSTS=backend,localhost
- CISO_ASSISTANT_URL=https://localhost:8443
- DJANGO_DEBUG=True
- AUTH_TOKEN_TTL=7200
volumes:
- ./db:/code/db

frontend:
container_name: frontend
environment:
- PUBLIC_BACKEND_API_URL=http://backend:8000/api
- PUBLIC_BACKEND_API_EXPOSED_URL=https://localhost:8443/api
- PROTOCOL_HEADER=x-forwarded-proto
- HOST_HEADER=x-forwarded-host

image: ghcr.io/intuitem/ciso-assistant-community/frontend:latest
depends_on:
- backend

caddy:
container_name: caddy
image: caddy:2.7.6
environment:
- CISO_ASSISTANT_URL=https://localhost:8443
depends_on:
- frontend
restart: unless-stopped
ports:
- 8443:8443
volumes:
- ./caddy_data:/data
command: |
sh -c 'echo $$CISO_ASSISTANT_URL "{
reverse_proxy /api/iam/sso/redirect/ backend:8000
reverse_proxy /api/accounts/saml/0/acs/ backend:8000
reverse_proxy /api/accounts/saml/0/acs/finish/ backend:8000
reverse_proxy /* frontend:3000
}" > Caddyfile && caddy run'
4 changes: 1 addition & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ services:
- ./caddy_data:/data
command: |
sh -c 'echo $$CISO_ASSISTANT_URL "{
reverse_proxy /api/iam/sso/redirect/ backend:8000
reverse_proxy /api/accounts/saml/0/acs/ backend:8000
reverse_proxy /api/accounts/saml/0/acs/finish/ backend:8000
reverse_proxy /api/* backend:8000
reverse_proxy /* frontend:3000
}" > Caddyfile && caddy run'

0 comments on commit 4eb2085

Please sign in to comment.