---
# System prepended metadata

title: Secure System Development Lab 1

---

# Secure System Development Lab 1

**Team Members:**
* Daniyar Cherekbashev (d.cherekbashev@innopolis.university)
* Gleb Statkevich (g.statkevich@innopolis.university)
* Daria Kalashnikova (d.kalashnikova@innopolis.university)

## Part I - Continuous Integration
### Task 1
**1. Q: What is the pipeline method of software development?**
    A: The pipeline method is a software development strategy that divides the process into units - stages (build, test, deploy). They are responsible for specific aspects, and each stage takes place sequentially.
**2. Q: What tasks and problems does the CI/CD process solve?**
    A: CI - Continuos Integration (mainly building and testing software artifacts), CD - Continuos Deployment (stage, at that we deploy artifacts/image to environment). The CI/CD process automates projects's code management tasks. It allows to: integrate code updates into a shared repository regularly, automatically test ensure quality (tests, security, etc.), quickly and efficiently deploy applications to production. CI/CD process minimizes manual human-factor errors, enhances teamwork, and speeds up software updates.
**3. Q: What kind of general stages are there in the CI/CD pipeline? List them in the correct sequence and then describe them.**
    A: Building - build software artifacts and then scan for vulnerabilities, Testing - test newly created artifacts. After that we can push artifacts to some artifacts repo (Nexus, Artifactory, e.g.), Deploying - deploy artifacts to environment.
**4. Q: Describe the difference(s) between unit testing and coverage testing.**
    A: Unit testing - test one or more software modules and focuses on individual components of code in isolation to ensure they work as expected. Often, this is a first stage of testing job in pipeline. Coverage testing usually measures proportion of source code being tested via autotests. While unit testing focuses on the correctness of individual units of code, coverage testing measures the effectiveness of the tests in covering the codebase.
**5. Q: What are Job Artifacts and Artifacts Storage?**
    A: Job Artifacts - built software in pipeline workspace, a result of the CI/CD stages (compiled code, test reports, or deployment packages). Artifacts Storage - a repository that store built artifacts for future reference/use (for troubleshooting, auditing, or rollback purposes.), also used for caching build dependencies and others.
 
### Task 2
1. Created user for our team:
![users](https://hackmd.io/_uploads/B1yLV0Sk0.png)


2. Application:
    <span style="color: green">main.py</span>
    ```python=
    from flask import Flask

    import datetime
    import pytz

    app = Flask(__name__)


    @app.route('/')
    def display_time() -> str:
        # Retrieving Innopolis (Moscow) timezone info
        timezone: datetime.tzinfo = pytz.timezone('Europe/Moscow')
        inno_time: str = datetime.datetime.now(timezone).strftime("%d %B, %H:%M:%S")
        return f'Hello Human! Time is: {inno_time}'


    if __name__ == '__main__':
        app.run()

    ```

    <span style="color: green">requirements.txt</span>
    ```
    pytz~=2022.7
    flask~=2.2.2
    ```
    Pushed changes to remote repo after adding public ssh key to the team user:
![gitlab-rep](https://hackmd.io/_uploads/S1DdN0B1R.png)
3. Deploying a Gitlab Runner:
Internal gitlab host was retrieved with `ip r` command.
![runner-terminal](https://hackmd.io/_uploads/Bybm7kUJ0.png)

    After deploying:
![runner](https://hackmd.io/_uploads/SyFHGJ81C.png)


Docker compose file of the previous steps:

<span style="color: green">docker-compose.yml</span>
```yaml=
version: '3.5'

services:
  gitlab:
    image: gitlab/gitlab-ee:latest
    hostname: ssd.inno.local
    restart: always
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        gitlab_rails['gitlab_shell_ssh_port'] = 8022
        external_url 'http://ssd.inno.local'
    ports:
      - "8022:22"
      - "8080:80"
      - "8443:443"
    volumes:
      - ./config/gitlab:/etc/gitlab
      - ./data/gitlab:/var/opt/gitlab
      - ./logs:/var/log/gitlab
    networks:
      gitlab:
        aliases:
          - 'ssd.inno.local'

  gitlab-runner:
    image: gitlab/gitlab-runner:alpine
    restart: unless-stopped
    depends_on:
      - gitlab
    volumes:
      - ./config/gitlab-runner:/etc/gitlab-runner
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - gitlab

networks:
  gitlab:
    driver: 'bridge'
```
    
## Part II - Continuous Deployment
### Task 3
<span style="color: green">Dockerfile</span>
```dockerfile
FROM docker.io/library/python:3.9.2 as build

COPY requirements.txt /

WORKDIR /app

RUN adduser --disabled-password puppet && chown -R puppet /app

COPY main.py ./
COPY requirements.txt ./

USER puppet
RUN python -m pip install -r /requirements.txt

EXPOSE 5000

CMD ["python", "main.py"]
```

Best practices used:
* The use of stable base image: Precise version python:3.9.2 is used to ensure consistency and avoid potential compatibility issues between different versions.
* Keeping layers immutable: Files or dependencies are not changed in the middle of the Dockerfile, as it can lead to inconsistencies and security vulnerabilities.
* Run as a non-root user: Application is run as a non-root user to minimize the potential security risks.

### Task 4
<span style="color: green">.gitlab-ci.yml</span>
```yaml=
stages:
  - build
  - deploy

default:
  image: docker:24.0.5
  services:
    - docker:24.0.5-dind
  before_script:
    - docker info

variables:
  DOCKER_HOST: tcp://docker:2375
  DOCKER_TLS_CERTDIR: ""

build-job:
  stage: build
  tags:
    - docker
  script:
    - docker build -t $DOCKERHUB_IMAGE -f Dockerfile .
    - docker login -u $DOCKERHUB_USER -p $DOCKERHUB_TOKEN docker.io
    - docker tag $DOCKERHUB_IMAGE:latest $DOCKERHUB_USER/$DOCKERHUB_IMAGE:latest
    - docker push $DOCKERHUB_USER/$DOCKERHUB_IMAGE:latest

deploy-job:
  image: ubuntu:latest
  stage: deploy
  tags:
    - default
  only:
    - master
  before_script:
    - apt-get -yq update
    - apt-get -yqq install ssh
    - install -m 600 -D /dev/null ~/.ssh/id_rsa
    - echo "$SSH_PRIVATE_KEY" | base64 -d > ~/.ssh/id_rsa
    - ssh-keyscan -H $SSH_HOST > ~/.ssh/known_hosts
  script:
    - ssh $SSH_USER@$SSH_HOST "docker run -d -p 5000:5000 $DOCKERHUB_USER/$DOCKERHUB_IMAGE:latest"
```

To make runner work and correctly resolve hosts, we should add `network_mode = "srv_gitlab"` (network name can be found with `docker network ls`) to the `/etc/gitlab-runner/config.toml` of our runner in `gitlab-runner` container. We should also add `privileged = true` to correctly run docker-in-docker container.
```toml
[[runners]]
    ...
    [runners.docker]
        privileged = true
        ...
        network_mode = "srv_gitlab"
```
Also, we should create CI/CD variables for our CI file:
![image](https://hackmd.io/_uploads/Hyji_Fd1C.png)

Passed jobs:
![image](https://hackmd.io/_uploads/rkC4KKO1R.png)

![image](https://hackmd.io/_uploads/r13_KKu1A.png)

![image](https://hackmd.io/_uploads/rkghKKuyC.png)

