├── roles ├── preparing │ ├── templates │ │ ├── resolv.conf.j2 │ │ ├── hosts.deny.j2 │ │ ├── hosts.allow.j2 │ │ ├── coredump.conf.j2 │ │ ├── timeout.j2 │ │ ├── journald.conf.j2 │ │ ├── limits.conf.j2 │ │ ├── hosts.j2 │ │ ├── logrotate.conf.j2 │ │ └── sshd_config.j2 │ ├── tasks │ │ ├── resolvconf.yml │ │ ├── fstab.yml │ │ ├── hosts.yml │ │ ├── limits.yml │ │ ├── main.yml │ │ ├── packages.yml │ │ ├── hardening.yaml │ │ ├── journalconf.yml │ │ └── auditd.yml │ └── handlers │ │ └── main.yaml ├── nginx │ ├── handlers │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── templates │ │ ├── nginx_minio_no_ssl.conf.j2 │ │ └── nginx_minio_with_ssl.conf.j2 ├── docker │ ├── templates │ │ └── daemon.j2 │ └── tasks │ │ └── main.yml └── minio │ ├── templates │ ├── .env │ ├── docker-compose.yml │ └── replication.sh.j2 │ ├── README.md │ └── tasks │ └── main.yml ├── images ├── minio.jpg ├── MinIO.drawio.png ├── dns-records.png ├── replication.png └── minio-console.png ├── ansible.cfg ├── inventory ├── inventory.ini └── group_vars │ └── all │ ├── minio.yml │ └── preparing.yaml ├── playbooks ├── nginx.yml └── minio.yml ├── LICENSE ├── script.py └── README.md /roles/preparing/templates/resolv.conf.j2: -------------------------------------------------------------------------------- 1 | nameserver 8.8.8.8 2 | nameserver 4.2.2.4 -------------------------------------------------------------------------------- /images/minio.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/siavashmhi/AutoMinIO/HEAD/images/minio.jpg -------------------------------------------------------------------------------- /roles/preparing/templates/hosts.deny.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | 3 | ALL: ALL 4 | -------------------------------------------------------------------------------- /images/MinIO.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/siavashmhi/AutoMinIO/HEAD/images/MinIO.drawio.png -------------------------------------------------------------------------------- /images/dns-records.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/siavashmhi/AutoMinIO/HEAD/images/dns-records.png -------------------------------------------------------------------------------- /images/replication.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/siavashmhi/AutoMinIO/HEAD/images/replication.png -------------------------------------------------------------------------------- /images/minio-console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/siavashmhi/AutoMinIO/HEAD/images/minio-console.png -------------------------------------------------------------------------------- /roles/nginx/handlers/main.yml: -------------------------------------------------------------------------------- 1 | - name: restart nginx 2 | service: 3 | name: nginx 4 | state: restarted 5 | -------------------------------------------------------------------------------- /roles/preparing/templates/hosts.allow.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | 3 | sshd : ALL : ALLOW 4 | ALL: LOCAL, 127.0.0.1 5 | -------------------------------------------------------------------------------- /roles/preparing/templates/coredump.conf.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | 3 | [Coredump] 4 | Storage=none 5 | ProcessSizeMax=0 6 | -------------------------------------------------------------------------------- /roles/preparing/templates/timeout.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ### 300 seconds == 5 minutes ## 3 | TMOUT={{ timeout_time }} 4 | readonly TMOUT 5 | export TMOUT -------------------------------------------------------------------------------- /roles/preparing/templates/journald.conf.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | 3 | [Journal] 4 | Storage=persistent 5 | ForwardToSyslog=yes 6 | Compress=yes 7 | -------------------------------------------------------------------------------- /ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | connection = smart 3 | timeout = 60 4 | deprecation_warnings = False 5 | host_key_checking = False 6 | pipelining=True 7 | forks=100 8 | -------------------------------------------------------------------------------- /inventory/inventory.ini: -------------------------------------------------------------------------------- 1 | [minio-servers] 2 | minio1 ansible_host=5.75.154.19 3 | minio2 ansible_host=88.198.197.57 4 | 5 | [load-balancer-servers] 6 | nginx-server ansible_host=128.140.11.51 7 | -------------------------------------------------------------------------------- /roles/preparing/templates/limits.conf.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | 3 | * hard maxlogins 10 4 | * hard core 0 5 | * soft nproc {{ limit_nproc_soft }} 6 | * hard nproc {{ limit_nproc_hard }} 7 | -------------------------------------------------------------------------------- /roles/docker/templates/daemon.j2: -------------------------------------------------------------------------------- 1 | { 2 | "log-driver": "json-file", 3 | "log-opts": { 4 | "max-size": "10m", 5 | "max-file": "3", 6 | "labels": "production_status", 7 | "env": "os,customer" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /roles/preparing/tasks/resolvconf.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: resolv.conf 3 | template: 4 | src: resolv.conf.j2 5 | dest: /etc/resolv.conf 6 | backup: 'yes' 7 | mode: 0644 8 | owner: root 9 | group: root 10 | -------------------------------------------------------------------------------- /roles/minio/templates/.env: -------------------------------------------------------------------------------- 1 | # restart policy 2 | RESTART_POLICY=unless-stopped 3 | 4 | # Minio user and pass 5 | MINIO_ROOT_USER={{ ROOT_USER }} 6 | MINIO_ROOT_PASSWORD={{ ROOT_PASSWORD }} 7 | ACCESS_KEY={{ ROOT_USER }} 8 | SECRET_KEY={{ ROOT_PASSWORD }} 9 | -------------------------------------------------------------------------------- /roles/preparing/templates/hosts.j2: -------------------------------------------------------------------------------- 1 | 127.0.0.1 localhost localhost.localdomain 2 | 127.0.1.1 {{ inventory_hostname }} 3 | 4 | # The following lines are desirable for IPv6 capable hosts 5 | ::1 localhost6 localhost6.localdomain 6 | ff02::1 ip6-allnodes 7 | ff02::2 ip6-allrouters -------------------------------------------------------------------------------- /playbooks/nginx.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: nginx-server 3 | become: true 4 | gather_facts: true 5 | name: setup nginx as a load balancer 6 | roles: 7 | - { role: roles/preparing, become: True, tags: preparing } 8 | - { role: roles/nginx, become: True, tags: nginx } 9 | -------------------------------------------------------------------------------- /roles/preparing/tasks/fstab.yml: -------------------------------------------------------------------------------- 1 | - name: remove /tmp from fstab 2 | mount: 3 | path: /tmp 4 | state: absent 5 | tags: 6 | - fstab 7 | 8 | - name: remove floppy from fstab 9 | ansible.builtin.lineinfile: 10 | path: /etc/fstab 11 | state: absent 12 | regexp: '^(.*)floppy(.*)$' 13 | tags: 14 | - fstab 15 | -------------------------------------------------------------------------------- /roles/preparing/templates/logrotate.conf.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | # CCE-80195-1 3 | 4 | daily 5 | {% if ansible_distribution == 'Ubuntu' %} 6 | su root syslog 7 | {% endif %} 8 | rotate 7 9 | create 10 | dateext 11 | compress 12 | 13 | compresscmd /usr/bin/xz 14 | uncompresscmd /usr/bin/unxz 15 | compressext .xz 16 | 17 | include /etc/logrotate.d 18 | -------------------------------------------------------------------------------- /playbooks/minio.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: minio-servers 3 | become: true 4 | gather_facts: true 5 | name: setup active-active replication minio with docker compose 6 | roles: 7 | - { role: roles/preparing, become: True, tags: preparing } 8 | - { role: roles/docker, bcome: True, tags: docker_setup } 9 | - { role: roles/minio, become: True, tags: minio } 10 | -------------------------------------------------------------------------------- /inventory/group_vars/all/minio.yml: -------------------------------------------------------------------------------- 1 | MINIO_CONSOLE_DOMAIN: console.cloudflow.ir # minio console domain 2 | MINIO_DOMAIN: minio.cloudflow.ir # minio api domain 3 | MINIO_BUCKETS: ("backup" "data" "database") # bucket names you want to created. 4 | ROOT_USER: "siavash" 5 | ROOT_PASSWORD: "4YJ97rJviWDPJ2mTEGxsXT4e4kHRmh" 6 | EMAIL_ADDRESS: "siavash@gmail.com" # for get notification from let's encrypt 7 | -------------------------------------------------------------------------------- /roles/preparing/tasks/hosts.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: hosts.allow 3 | ansible.builtin.template: 4 | src: hosts.allow.j2 5 | dest: /etc/hosts.allow 6 | backup: 'yes' 7 | mode: 0644 8 | owner: root 9 | group: root 10 | 11 | - name: hosts.deny 12 | ansible.builtin.template: 13 | src: hosts.deny.j2 14 | dest: /etc/hosts.deny 15 | backup: 'yes' 16 | mode: 0644 17 | owner: root 18 | group: root 19 | -------------------------------------------------------------------------------- /roles/preparing/tasks/limits.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: limits.conf 3 | ansible.builtin.template: 4 | src: limits.conf.j2 5 | dest: /etc/security/limits.conf 6 | backup: 'yes' 7 | mode: 0644 8 | owner: root 9 | group: root 10 | 11 | - name: coredump.conf 12 | ansible.builtin.template: 13 | src: coredump.conf.j2 14 | dest: /etc/systemd/coredump.conf 15 | backup: 'yes' 16 | mode: 0644 17 | owner: root 18 | group: root 19 | -------------------------------------------------------------------------------- /roles/preparing/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: insall package 3 | import_tasks: packages.yml 4 | tags: install_packages 5 | 6 | - name: change limit.conf 7 | import_tasks: limits.yml 8 | tags: tuning 9 | 10 | - name: configure ssh service 11 | import_tasks: hardening.yaml 12 | tags: hardening 13 | 14 | - name: host file configure 15 | import_tasks: hosts.yml 16 | tags: hardening 17 | 18 | - name: fstab config 19 | import_tasks: fstab.yml 20 | tags: hardening 21 | -------------------------------------------------------------------------------- /roles/preparing/handlers/main.yaml: -------------------------------------------------------------------------------- 1 | - name: Restart ssh 2 | systemd: 3 | name: ssh 4 | state: restarted 5 | 6 | - name: Restart ntp 7 | systemd: 8 | name: ntp 9 | state: restarted 10 | 11 | - name: restart auditd 12 | ansible.builtin.command: service auditd restart 13 | 14 | - name: generate auditd 15 | ansible.builtin.command: augenrules 16 | 17 | - name: reload systemd 18 | ansible.builtin.systemd: 19 | daemon_reload: 'yes' 20 | 21 | - name: update cracklib debian 22 | ansible.builtin.command: update-cracklib 23 | -------------------------------------------------------------------------------- /roles/preparing/tasks/packages.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # tasks file for hardening 3 | - name: Update and upgrade apt packages 4 | apt: 5 | upgrade: yes 6 | update_cache: yes 7 | cache_valid_time: 86400 8 | 9 | - name: Install basic tools 10 | apt: 11 | name: "{{ packages }}" 12 | state: present 13 | force_apt_get: yes 14 | update_cache: yes 15 | 16 | - name: Set hostname 17 | hostname: 18 | name: '{{ inventory_hostname }}' 19 | 20 | - name: Fix /etc/hosts 21 | template: 22 | src: "hosts.j2" 23 | dest: "/etc/hosts" 24 | -------------------------------------------------------------------------------- /roles/preparing/tasks/hardening.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Stop and Disable ufw service if started 3 | ansible.builtin.service: 4 | name: ufw 5 | state: stopped 6 | enabled: no 7 | 8 | - name: Make timout configuration file. 9 | template: 10 | src: timeout.j2 11 | dest: /etc/profile.d/timout-settings.sh 12 | 13 | - name: Set timezone to Asia/Tehran 14 | community.general.timezone: 15 | name: Asia/Tehran 16 | notify: Restart ntp 17 | 18 | - name: Make sshd configuration file. 19 | template: 20 | src: sshd_config.j2 21 | dest: /etc/ssh/sshd_config 22 | notify: Restart ssh 23 | 24 | -------------------------------------------------------------------------------- /roles/minio/templates/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | networks: 4 | web_net: 5 | external: true 6 | driver: bridge 7 | 8 | volumes: 9 | minio_data: 10 | 11 | services: 12 | minio: 13 | image: minio/minio:RELEASE.2024-07-16T23-46-41Z 14 | hostname: minio 15 | restart: ${RESTART_POLICY} 16 | environment: 17 | MINIO_ROOT_USER: ${MINIO_ROOT_USER} 18 | MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD} 19 | MINIO_ACCESS_KEY: ${ACCESS_KEY} 20 | MINIO_SECRET_KEY: ${SECRET_KEY} 21 | volumes: 22 | - minio_data:/data 23 | command: server --console-address ":9001" /data 24 | networks: 25 | - web_net 26 | ports: 27 | - 9000:9000 28 | - 9001:9001 29 | -------------------------------------------------------------------------------- /roles/docker/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - name: install dependency 2 | apt: 3 | name: "{{item}}" 4 | state: present 5 | update_cache: yes 6 | loop: 7 | - apt-transport-https 8 | - ca-certificates 9 | - curl 10 | - gnupg-agent 11 | - software-properties-common 12 | 13 | - name: Download and add Docker GPG key 14 | shell: curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - 15 | 16 | - name: add docker repo 17 | apt_repository: 18 | repo: deb https://download.docker.com/linux/ubuntu bionic stable 19 | state: present 20 | 21 | - name: install docker 22 | apt: 23 | name: "{{item}}" 24 | state: latest 25 | update_cache: yes 26 | loop: 27 | - docker-ce 28 | - docker-ce-cli 29 | - containerd.io 30 | 31 | - name: Make docker configuration file. 32 | template: 33 | src: daemon.j2 34 | dest: /etc/docker/daemon.json 35 | 36 | - name: start and enable docker 37 | service: 38 | name: docker 39 | state: started 40 | 41 | - name: restart docker 42 | service: 43 | name: docker 44 | state: restarted 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2024 Scott Chacon and others 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /roles/minio/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | BSD 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /inventory/group_vars/all/preparing.yaml: -------------------------------------------------------------------------------- 1 | # basic package list for installation 2 | packages: 3 | - sysstat 4 | - wget 5 | - git 6 | - vim 7 | - nano 8 | - bash-completion 9 | - curl 10 | - htop 11 | - iftop 12 | - jq 13 | - ncdu 14 | - unzip 15 | - net-tools 16 | - dnsutils 17 | - atop 18 | - sudo 19 | - ntp 20 | - fail2ban 21 | - software-properties-common 22 | - apache2-utils 23 | - tcpdump 24 | - telnet 25 | - axel 26 | - iptables-persistent 27 | - ntp 28 | - auditd 29 | - libpwquality-common 30 | - cracklib-runtime 31 | - python-is-python3 32 | - tree 33 | 34 | # sshd configuration 35 | sshd_config: 36 | Port: "{{ ansible_port }}" 37 | ListenAddress: 0.0.0.0 38 | PermitRootLogin: without-password 39 | PasswordAuthentication: "yes" 40 | AllowUsers: root 41 | AllowGroups: root 42 | 43 | 44 | # setion timeout setting (seconds) 45 | timeout_time: 600 46 | 47 | # auditd vars 48 | auditd_apply_audit_rules: 'yes' 49 | auditd_action_mail_acct: root 50 | auditd_admin_space_left_action: suspend 51 | auditd_disk_error_action: suspend 52 | auditd_disk_full_action: suspend 53 | auditd_max_log_file: 8 54 | auditd_max_log_file_action: keep_logs 55 | auditd_mode: 1 56 | auditd_num_logs: 5 57 | auditd_space_left: 75 58 | auditd_space_left_action: email 59 | grub_audit_backlog_cmdline: audit_backlog_limit=8192 60 | grub_audit_cmdline: audit=1 61 | 62 | # Limit.conf variables 63 | limit_nofile_hard: 1024 64 | limit_nofile_soft: 512 65 | limit_nproc_hard: 1024 66 | limit_nproc_soft: 512 67 | -------------------------------------------------------------------------------- /script.py: -------------------------------------------------------------------------------- 1 | import os 2 | from faker import Faker 3 | from time import sleep 4 | 5 | # Configuration 6 | MINIO_ENDPOINT = "https://minio.cloudflow.ir" # Change to your MinIO server endpoint 7 | ACCESS_KEY = "siavash" # Replace with your MinIO access key 8 | SECRET_KEY = "4YJ97rJviWDPJ2mTEGxsXT4e4kHRmh" # Replace with your MinIO secret key 9 | BUCKET_NAME = "backup" # Replace with your MinIO bucket name 10 | NUM_FILES = 10 # Number of fake files to generate 11 | 12 | # Initialize Faker and MinIO client 13 | fake = Faker() 14 | 15 | try: 16 | os.system(f"mc alias set client {MINIO_ENDPOINT} {ACCESS_KEY} {SECRET_KEY}") 17 | except Exception as error: 18 | print(error) 19 | 20 | # Generate fake files and upload to MinIO 21 | for i in range(NUM_FILES): 22 | # Generate fake content 23 | file_name = f"fake_file_{i + 1}.txt" 24 | content = fake.text(max_nb_chars=200) # Generate random text content 25 | 26 | # Save the content to a local file 27 | with open(file_name, 'w') as f: 28 | f.write(content) 29 | 30 | # Upload the file to MinIO 31 | try: 32 | # minio_client.fput_object(BUCKET_NAME, file_name, file_name) 33 | os.system(f"mc cp {file_name} client/{BUCKET_NAME}") 34 | print(f"Uploaded {file_name} to bucket {BUCKET_NAME}") 35 | except Exception as e: 36 | print(f"Error uploading {file_name}: {e}") 37 | 38 | # Optionally, remove the local file after uploading 39 | os.remove(file_name) 40 | sleep(3) 41 | 42 | print("All files uploaded successfully.") 43 | -------------------------------------------------------------------------------- /roles/nginx/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # 1. Install NGINX and Certbot 2 | - name: Install NGINX and Certbot 3 | apt: 4 | name: 5 | - nginx 6 | - python3-certbot-nginx 7 | state: present 8 | update_cache: yes 9 | 10 | # 2. Create NGINX config without SSL for MinIO and Console 11 | - name: Configure NGINX without SSL for MinIO Load Balancing 12 | template: 13 | src: nginx_minio_no_ssl.conf.j2 14 | dest: /etc/nginx/sites-available/minio.conf 15 | 16 | # 3. Enable the NGINX site configuration 17 | - name: Enable NGINX site 18 | file: 19 | src: /etc/nginx/sites-available/minio.conf 20 | dest: /etc/nginx/sites-enabled/minio.conf 21 | state: link 22 | 23 | # 4. Remove the default NGINX config if present 24 | - name: Remove default NGINX configuration 25 | file: 26 | path: /etc/nginx/sites-enabled/default 27 | state: absent 28 | 29 | # 5. Start and Test NGINX (without SSL) 30 | - name: Ensure NGINX is running 31 | service: 32 | name: nginx 33 | state: started 34 | 35 | # 6. Obtain SSL certificates using Certbot 36 | - name: Obtain SSL certificates for MinIO and MinIO Console 37 | command: > 38 | certbot --nginx -d {{ MINIO_DOMAIN }} -d {{ MINIO_CONSOLE_DOMAIN }} --non-interactive --agree-tos --email {{ EMAIL_ADDRESS }} 39 | notify: restart nginx 40 | 41 | # 7. Configure NGINX with SSL for MinIO and Console 42 | - name: Configure NGINX with SSL for MinIO Load Balancing 43 | template: 44 | src: nginx_minio_with_ssl.conf.j2 45 | dest: /etc/nginx/sites-available/minio.conf 46 | notify: restart nginx 47 | -------------------------------------------------------------------------------- /roles/minio/templates/replication.sh.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Main variables 4 | ACCESS_KEY="{{ ROOT_USER }}" 5 | SECRET_KEY="{{ ROOT_PASSWORD }}" 6 | 7 | # URLs for MinIO endpoints 8 | MINIO1_URL="http://{{ hostvars[groups['minio-servers'][0]].ansible_host }}:9000" 9 | MINIO2_URL="http://{{ hostvars[groups['minio-servers'][1]].ansible_host }}:9000" 10 | 11 | # List of buckets to create 12 | BUCKETS={{ MINIO_BUCKETS }} 13 | 14 | # Helper function to check for errors and exit if a command fails 15 | check_command() { 16 | if [ $? -ne 0 ]; then 17 | echo "Error: $1 failed." 18 | exit 1 19 | else 20 | echo "$1 succeeded." 21 | fi 22 | } 23 | 24 | # Function to set an alias for MinIO 25 | set_minio_alias() { 26 | local alias_name=$1 27 | local url=$2 28 | local access_key=$3 29 | local secret_key=$4 30 | 31 | echo "Setting alias for $alias_name..." 32 | mc alias set "$alias_name" "$url" "$access_key" "$secret_key" 33 | check_command "Alias set for $alias_name" 34 | } 35 | 36 | # Function to create a bucket 37 | create_bucket() { 38 | local alias_name=$1 39 | local bucket_name=$2 40 | 41 | echo "Creating bucket $bucket_name on $alias_name..." 42 | mc mb "$alias_name/$bucket_name" 43 | check_command "Bucket creation for $bucket_name" 44 | } 45 | 46 | # Set aliases for minio1 and minio2 47 | set_minio_alias "minio-master" "$MINIO1_URL" "$ACCESS_KEY" "$SECRET_KEY" 48 | set_minio_alias "minio-slave" "$MINIO2_URL" "$ACCESS_KEY" "$SECRET_KEY" 49 | 50 | # Create the buckets on minio1 using a for loop 51 | for bucket in "${BUCKETS[@]}"; do 52 | create_bucket "minio-master" "$bucket" 53 | done 54 | 55 | # Set up replication from minio1 to minio2 56 | mc admin replicate add minio-master minio-slave 57 | 58 | echo "All tasks completed successfully." 59 | -------------------------------------------------------------------------------- /roles/preparing/tasks/journalconf.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: systemd journald.conf 3 | ansible.builtin.template: 4 | src: journald.conf.j2 5 | dest: /etc/systemd/journald.conf 6 | backup: 'yes' 7 | mode: 0644 8 | owner: root 9 | group: root 10 | notify: 11 | - reload systemd 12 | 13 | - name: logrotate.conf 14 | ansible.builtin.template: 15 | src: logrotate.conf.j2 16 | dest: /etc/logrotate.conf 17 | backup: 'yes' 18 | mode: 0644 19 | owner: root 20 | group: root 21 | 22 | - name: cron.daily logrotate 23 | ansible.builtin.lineinfile: 24 | line: "/usr/sbin/logrotate /etc/logrotate.conf" 25 | dest: /etc/cron.daily/logrotate 26 | mode: 0750 27 | state: present 28 | create: 'yes' 29 | 30 | - name: stat rsyslog.conf 31 | ansible.builtin.stat: 32 | path: /etc/rsyslog.conf 33 | register: rsyslogconf 34 | 35 | - name: get rsyslog.conf FileCreateMode 36 | environment: 37 | PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 38 | ansible.builtin.shell: grep "^$FileCreateMode" /etc/rsyslog.conf 39 | register: rsyslog_filecreatemode 40 | changed_when: false 41 | when: rsyslogconf.stat.exists 42 | 43 | - name: set rsyslog.conf FileCreateMode 44 | ansible.builtin.lineinfile: 45 | regexp: '^\$FileCreateMode' 46 | line: '$FileCreateMode 0600' 47 | dest: /etc/rsyslog.conf 48 | mode: 0640 49 | state: present 50 | create: 'no' 51 | when: rsyslogconf.stat.exists and rsyslog_filecreatemode.stdout.find('FileCreateMode') != -1 52 | 53 | - name: set rsyslog.d FileCreateMode 54 | ansible.builtin.lineinfile: 55 | regexp: '^\$FileCreateMode' 56 | line: '$FileCreateMode 0600' 57 | dest: /etc/rsyslog.d/99-filecreatemode.conf 58 | mode: 0644 59 | state: present 60 | create: 'yes' 61 | -------------------------------------------------------------------------------- /roles/nginx/templates/nginx_minio_no_ssl.conf.j2: -------------------------------------------------------------------------------- 1 | upstream minio_s3 { 2 | least_conn; 3 | {% for host in groups['minio-servers'] %} 4 | server {{ hostvars[host].ansible_host }}:9000; 5 | {% endfor %} 6 | } 7 | 8 | upstream minio_console { 9 | least_conn; 10 | server {{ hostvars[groups['minio-servers'][0]].ansible_host }}:9001; 11 | } 12 | 13 | server { 14 | listen 80; 15 | listen [::]:80; 16 | server_name {{ MINIO_DOMAIN }}; 17 | 18 | ignore_invalid_headers off; 19 | client_max_body_size 0; 20 | proxy_buffering off; 21 | proxy_request_buffering off; 22 | 23 | location / { 24 | proxy_set_header Host $http_host; 25 | proxy_set_header X-Real-IP $remote_addr; 26 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 27 | proxy_set_header X-Forwarded-Proto $scheme; 28 | proxy_connect_timeout 300; 29 | proxy_http_version 1.1; 30 | proxy_set_header Connection ""; 31 | chunked_transfer_encoding off; 32 | proxy_pass http://minio_s3; 33 | } 34 | } 35 | 36 | server { 37 | listen 80; 38 | listen [::]:80; 39 | server_name {{ MINIO_CONSOLE_DOMAIN }}; 40 | 41 | ignore_invalid_headers off; 42 | client_max_body_size 0; 43 | proxy_buffering off; 44 | proxy_request_buffering off; 45 | 46 | location / { 47 | proxy_set_header Host $http_host; 48 | proxy_set_header X-Real-IP $remote_addr; 49 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 50 | proxy_set_header X-Forwarded-Proto $scheme; 51 | proxy_set_header X-NginX-Proxy true; 52 | real_ip_header X-Real-IP; 53 | proxy_connect_timeout 300; 54 | proxy_http_version 1.1; 55 | proxy_set_header Upgrade $http_upgrade; 56 | proxy_set_header Connection "upgrade"; 57 | chunked_transfer_encoding off; 58 | proxy_pass http://minio_console; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /roles/minio/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - name: Create MinIO data directory 2 | file: 3 | path: "/opt/minio" 4 | state: directory 5 | owner: root 6 | group: root 7 | mode: '0755' 8 | 9 | - name: Copy Docker Compose file 10 | template: 11 | src: docker-compose.yml 12 | dest: /opt/minio/docker-compose.yml 13 | 14 | - name: Copy Docker Compose file 15 | template: 16 | src: .env 17 | dest: /opt/minio/.env 18 | 19 | - name: Create Docker network 20 | docker_network: 21 | name: web_net 22 | driver: bridge 23 | state: present 24 | 25 | - name: Start MinIO service using Docker Compose 26 | community.docker.docker_compose_v2: 27 | project_src: "/opt/minio" 28 | files: 29 | - docker-compose.yml 30 | 31 | - name: Install dependencies (wget) 32 | apt: 33 | name: wget 34 | state: present 35 | update_cache: yes 36 | 37 | - name: Download MinIO Client (mc) with curl 38 | shell: | 39 | curl -o /usr/local/bin/mc https://dl.min.io/client/mc/release/linux-amd64/mc 40 | chmod +x /usr/local/bin/mc 41 | args: 42 | creates: /usr/local/bin/mc 43 | 44 | - name: Verify mc installation 45 | command: mc --version 46 | register: mc_version 47 | ignore_errors: true 48 | 49 | - name: Ensure mc is installed 50 | debug: 51 | msg: "MinIO Client (mc) version: {{ mc_version.stdout }}" 52 | when: mc_version.rc == 0 53 | 54 | - name: Ensure MinIO containers are running 55 | docker_container_info: 56 | name: "minio" 57 | register: result 58 | 59 | - name: Debug MinIO containers 60 | debug: 61 | var: result 62 | 63 | - name: Copy the replication script to the server 64 | template: 65 | src: replication.sh.j2 66 | dest: /opt/replication.sh 67 | mode: '0755' 68 | when: inventory_hostname == 'minio1' 69 | 70 | - name: Run the replication script using shell module 71 | shell: /opt/replication.sh 72 | when: inventory_hostname == 'minio1' 73 | register: script_output 74 | 75 | - name: Debug replication.sh script 76 | debug: 77 | var: script_output 78 | when: inventory_hostname == 'minio1' 79 | -------------------------------------------------------------------------------- /roles/nginx/templates/nginx_minio_with_ssl.conf.j2: -------------------------------------------------------------------------------- 1 | upstream minio_s3 { 2 | least_conn; 3 | {% for host in groups['minio-servers'] %} 4 | server {{ hostvars[host].ansible_host }}:9000; 5 | {% endfor %} 6 | } 7 | 8 | upstream minio_console { 9 | least_conn; 10 | server {{ hostvars[groups['minio-servers'][0]].ansible_host }}:9001; 11 | } 12 | 13 | server { 14 | listen 80; 15 | listen [::]:80; 16 | server_name {{ MINIO_DOMAIN }}; 17 | return 301 https://$server_name$request_uri; 18 | } 19 | 20 | server { 21 | listen 443 ssl; 22 | listen [::]:443 ssl; 23 | server_name {{ MINIO_DOMAIN }}; 24 | 25 | ssl_certificate /etc/letsencrypt/live/{{ MINIO_DOMAIN }}/fullchain.pem; 26 | ssl_certificate_key /etc/letsencrypt/live/{{ MINIO_DOMAIN }}/privkey.pem; 27 | ssl_protocols TLSv1.2 TLSv1.3; 28 | ssl_prefer_server_ciphers on; 29 | 30 | ignore_invalid_headers off; 31 | client_max_body_size 0; 32 | proxy_buffering off; 33 | proxy_request_buffering off; 34 | 35 | location / { 36 | proxy_set_header Host $http_host; 37 | proxy_set_header X-Real-IP $remote_addr; 38 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 39 | proxy_set_header X-Forwarded-Proto $scheme; 40 | proxy_connect_timeout 300; 41 | proxy_http_version 1.1; 42 | proxy_set_header Connection ""; 43 | chunked_transfer_encoding off; 44 | proxy_pass http://minio_s3; 45 | } 46 | } 47 | 48 | server { 49 | listen 80; 50 | listen [::]:80; 51 | server_name {{ MINIO_CONSOLE_DOMAIN }}; 52 | return 301 https://$server_name$request_uri; 53 | } 54 | 55 | server { 56 | listen 443 ssl; 57 | listen [::]:443 ssl; 58 | server_name {{ MINIO_CONSOLE_DOMAIN }}; 59 | 60 | ssl_certificate /etc/letsencrypt/live/{{ MINIO_DOMAIN }}/fullchain.pem; 61 | ssl_certificate_key /etc/letsencrypt/live/{{ MINIO_DOMAIN }}/privkey.pem; 62 | ssl_protocols TLSv1.2 TLSv1.3; 63 | ssl_prefer_server_ciphers on; 64 | 65 | ignore_invalid_headers off; 66 | client_max_body_size 0; 67 | proxy_buffering off; 68 | proxy_request_buffering off; 69 | 70 | location / { 71 | proxy_set_header Host $http_host; 72 | proxy_set_header X-Real-IP $remote_addr; 73 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 74 | proxy_set_header X-Forwarded-Proto $scheme; 75 | proxy_set_header X-NginX-Proxy true; 76 | real_ip_header X-Real-IP; 77 | proxy_connect_timeout 300; 78 | proxy_http_version 1.1; 79 | proxy_set_header Upgrade $http_upgrade; 80 | proxy_set_header Connection "upgrade"; 81 | chunked_transfer_encoding off; 82 | proxy_pass http://minio_console; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /roles/preparing/tasks/auditd.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: set Debian audit grub cmdline 3 | ansible.builtin.lineinfile: 4 | line: 'GRUB_CMDLINE_LINUX="$GRUB_CMDLINE_LINUX {{ grub_audit_cmdline }} {{ grub_audit_backlog_cmdline }}"' 5 | dest: /etc/default/grub.d/99-hardening-audit.cfg 6 | state: present 7 | create: 'yes' 8 | mode: 0755 9 | owner: root 10 | group: root 11 | 12 | - name: set audit action_mail_acct 13 | ansible.builtin.lineinfile: 14 | regexp: "^action_mail_acct =" 15 | line: "action_mail_acct = {{ auditd_action_mail_acct }}" 16 | dest: /etc/audit/auditd.conf 17 | mode: 0640 18 | state: present 19 | create: 'no' 20 | 21 | - name: set audit admin_space_left_action 22 | ansible.builtin.lineinfile: 23 | regexp: "^admin_space_left_action = " 24 | line: "admin_space_left_action = {{ auditd_admin_space_left_action }}" 25 | dest: /etc/audit/auditd.conf 26 | mode: 0640 27 | state: present 28 | create: 'no' 29 | 30 | - name: set audit disk_error_action 31 | ansible.builtin.lineinfile: 32 | regexp: "^disk_error_action =" 33 | line: "disk_error_action = {{ auditd_disk_error_action }}" 34 | dest: /etc/audit/auditd.conf 35 | mode: 0640 36 | state: present 37 | create: 'no' 38 | 39 | - name: set audit disk_full_action 40 | ansible.builtin.lineinfile: 41 | regexp: "^disk_full_action =" 42 | line: "disk_full_action = {{ auditd_disk_full_action }}" 43 | dest: /etc/audit/auditd.conf 44 | mode: 0640 45 | state: present 46 | create: 'no' 47 | 48 | - name: set audit max_log_file 49 | ansible.builtin.lineinfile: 50 | regexp: "^max_log_file =" 51 | line: "max_log_file = {{ auditd_max_log_file }}" 52 | dest: /etc/audit/auditd.conf 53 | mode: 0640 54 | state: present 55 | create: 'no' 56 | 57 | - name: set audit max_log_file_action 58 | ansible.builtin.lineinfile: 59 | regexp: "^max_log_file_action =" 60 | line: "max_log_file_action = {{ auditd_max_log_file_action }}" 61 | dest: /etc/audit/auditd.conf 62 | mode: 0640 63 | state: present 64 | create: 'no' 65 | 66 | - name: set audit num_logs 67 | ansible.builtin.lineinfile: 68 | regexp: "^num_logs =" 69 | line: "num_logs = {{ auditd_num_logs }}" 70 | dest: /etc/audit/auditd.conf 71 | mode: 0640 72 | state: present 73 | create: 'no' 74 | 75 | - name: set audit space_left 76 | ansible.builtin.lineinfile: 77 | regexp: "^space_left =" 78 | line: "space_left = {{ auditd_space_left }}" 79 | dest: /etc/audit/auditd.conf 80 | mode: 0640 81 | state: present 82 | create: 'no' 83 | 84 | - name: set audit space_left_action 85 | ansible.builtin.lineinfile: 86 | regexp: "^space_left_action =" 87 | line: "space_left_action = {{ auditd_space_left_action }}" 88 | dest: /etc/audit/auditd.conf 89 | mode: 0640 90 | state: present 91 | create: 'no' 92 | 93 | - name: audit.rules 94 | ansible.builtin.template: 95 | src: hardening.rules.j2 96 | dest: /etc/audit/rules.d/hardening.rules 97 | backup: 'yes' 98 | mode: 0600 99 | owner: root 100 | group: root 101 | when: auditd_apply_audit_rules|bool 102 | notify: 103 | - generate auditd 104 | - restart auditd 105 | 106 | -------------------------------------------------------------------------------- /roles/preparing/templates/sshd_config.j2: -------------------------------------------------------------------------------- 1 | Include /etc/ssh/sshd_config.d/*.conf 2 | 3 | Port {{ sshd_config.Port|default('22') }} 4 | #AddressFamily any 5 | ListenAddress {{ sshd_config.ListenAddress|default('0.0.0.0') }} 6 | #ListenAddress :: 7 | 8 | #HostKey /etc/ssh/ssh_host_rsa_key 9 | #HostKey /etc/ssh/ssh_host_ecdsa_key 10 | #HostKey /etc/ssh/ssh_host_ed25519_key 11 | 12 | # Ciphers and keying 13 | #RekeyLimit default none 14 | 15 | # Logging 16 | #SyslogFacility AUTH 17 | LogLevel VERBOSE 18 | 19 | # Authentication: 20 | 21 | #LoginGraceTime 2m 22 | PermitRootLogin {{ sshd_config.PermitRootLogin|default('without-password') }} 23 | #StrictModes yes 24 | MaxAuthTries 3 25 | MaxSessions 2 26 | 27 | #PubkeyAuthentication yes 28 | 29 | # Expect .ssh/authorized_keys2 to be disregarded by default in future. 30 | #AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2 31 | 32 | #AuthorizedPrincipalsFile none 33 | 34 | # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts 35 | #HostbasedAuthentication no 36 | # Change to yes if you don't trust ~/.ssh/known_hosts for 37 | # HostbasedAuthentication 38 | #IgnoreUserKnownHosts no 39 | # Don't read the user's ~/.rhosts and ~/.shosts files 40 | #IgnoreRhosts yes 41 | 42 | # To disable tunneled clear text passwords, change to no here! 43 | PasswordAuthentication {{ sshd_config.PasswordAuthentication|default('yes') }} 44 | #PermitEmptyPasswords no 45 | 46 | # Change to yes to enable challenge-response passwords (beware issues with 47 | # some PAM modules and threads) 48 | ChallengeResponseAuthentication no 49 | 50 | # Kerberos options 51 | #KerberosAuthentication no 52 | #KerberosOrLocalPasswd yes 53 | #KerberosTicketCleanup yes 54 | #KerberosGetAFSToken no 55 | 56 | # GSSAPI options 57 | #GSSAPIAuthentication no 58 | #GSSAPICleanupCredentials yes 59 | #GSSAPIStrictAcceptorCheck yes 60 | #GSSAPIKeyExchange no 61 | 62 | # Set this to 'yes' to enable PAM authentication, account processing, 63 | # and session processing. If this is enabled, PAM authentication will 64 | # be allowed through the ChallengeResponseAuthentication and 65 | # PasswordAuthentication. Depending on your PAM configuration, 66 | # PAM authentication via ChallengeResponseAuthentication may bypass 67 | # the setting of "PermitRootLogin without-password". 68 | # If you just want the PAM account and session checks to run without 69 | # PAM authentication, then enable this but set PasswordAuthentication 70 | # and ChallengeResponseAuthentication to 'no'. 71 | UsePAM yes 72 | 73 | AllowAgentForwarding no 74 | AllowTcpForwarding no 75 | #GatewayPorts no 76 | X11Forwarding no 77 | #X11DisplayOffset 10 78 | #X11UseLocalhost yes 79 | #PermitTTY yes 80 | PrintMotd no 81 | #PrintLastLog yes 82 | TCPKeepAlive no 83 | #PermitUserEnvironment no 84 | Compression no 85 | #ClientAliveInterval 0 86 | ClientAliveCountMax 2 87 | #UseDNS no 88 | #PidFile /var/run/sshd.pid 89 | #MaxStartups 10:30:100 90 | #PermitTunnel no 91 | #ChrootDirectory none 92 | #VersionAddendum none 93 | 94 | # no default banner path 95 | Banner /etc/issue 96 | 97 | # Allow client to pass locale environment variables 98 | AcceptEnv LANG LC_* 99 | 100 | # override default of no subsystems 101 | Subsystem sftp /usr/lib/openssh/sftp-server 102 | 103 | # Example of overriding settings on a per-user basis 104 | #Match User anoncvs 105 | # X11Forwarding no 106 | # AllowTcpForwarding no 107 | # PermitTTY no 108 | # ForceCommand cvs server 109 | 110 | {% if sshd_config.AllowUsers is defined %} 111 | AllowUsers {{ sshd_config.AllowUsers }} 112 | {% endif %} 113 | {% if sshd_config.AllowGroups is defined %} 114 | AllowGroups {{ sshd_config.AllowGroups }} 115 | {% endif %} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Setup high available MinIO object storage system with Ansible. 2 | 3 | This project provides an end-to-end automation solution using Ansible for deploying a high available MinIO object storage system in active-active replication mode. The setup involves configuring two MinIO instances using Docker Compose and use nginx for load balancer. 4 | 5 | ![minio high level design](./images/MinIO.drawio.png "minio high level design") 6 | 7 | ## Key components of the project: 8 | 1. Ansible Playbooks: Automate the deployment and configuration of MinIO nodes. 9 | 2. Docker Compose: Used for container platform, ensuring MinIO instances run in isolated environments. 10 | 3. nginx: Used for load balancer. 11 | 4. Bash Script (replication.sh): A custom script that configures the active-active replication between the two buckets in two MinIO instances, ensuring data synchronization across both sites. 12 | 13 | ## Prerequisites 14 | 15 | 1. **Ansible:** Ensure Ansible is installed on your system. 16 | 2. **SSH:** You have to ssh access to your servers. 17 | 18 | ### Step 1: Clone the Repository 19 | 20 | To begin, clone this repository to your local machine: 21 | 22 | ```bash 23 | git clone https://github.com/siavashmhi/AutoMinIO.git 24 | cd AutoMinIO 25 | ``` 26 | 27 | ### Step 2: Modify ansible inventory.ini file 28 | 29 | You have to set server IPs in this file. 30 | 31 | ```bash 32 | cat inventory/inventory.ini 33 | 34 | [minio-servers] 35 | minio1 ansible_host=5.75.154.19 36 | minio2 ansible_host=88.198.197.57 37 | 38 | [load-balancer-servers] 39 | nginx-server ansible_host=128.140.11.51 40 | 41 | ``` 42 | ### Step 3: Modify minio.yml ansible variable file. 43 | 44 | ```bash 45 | cat inventory/group_vars/all/minio.yml 46 | 47 | MINIO_CONSOLE_DOMAIN: console.cloudflow.ir # minio console domain 48 | MINIO_DOMAIN: minio.cloudflow.ir # minio api domain 49 | MINIO_BUCKETS: ("backup" "data" "database") # bucket names you want to created. 50 | ROOT_USER: "siavash" 51 | ROOT_PASSWORD: "4YJ97rJviWDPJ2mTEGxsXT4e4kHRmh" 52 | EMAIL_ADDRESS: "siavash@gmail.com" # for get notification from let's encrypt 53 | 54 | ``` 55 | 56 | ### Step 4: Run minio.yml ansible playbook. 57 | 58 | ```bash 59 | ansible-playbook -i inventory/inventory.ini playbooks/minio.yml 60 | ``` 61 | 62 | ### Step 5: set dns records for minio console and minio api. 63 | 64 | DNS Records should point to the load balancer server (nginx server). 65 | 66 | ![dns records](./images/dns-records.png "dns records") 67 | 68 | ### Step 6: Run nginx.yml ansible playbook. 69 | 70 | This ansible playbook is for config your load balancer server. 71 | 72 | ```bash 73 | ansible-playbook -i inventory/inventory.ini playbooks/nginx.yml 74 | ``` 75 | 76 | ### After completing all the steps, you will see the MinIO console with your domain for example console.cloudflow.ir. 77 | 78 | ![site replication](./images/replication.png "site replication") 79 | 80 | ### Step 7: Test Minio with upload fake data. 81 | 82 | You can test Minio service with upload fake data to one bucket in Minio. 83 | 84 | 1. **Ensure Python is installed on your system.** 85 | 2. **Ensure mc (minio client) is installed on your system.** 86 | 87 | ```bash 88 | # install faker package for generate fake data. 89 | pip install Faker 90 | 91 | # Modify variables in script.py 92 | cat script.py 93 | 94 | MINIO_ENDPOINT = "https://minio.cloudflow.ir" # Change to your MinIO server endpoint 95 | ACCESS_KEY = "siavash" # Replace with your MinIO access key 96 | SECRET_KEY = "4YJ97rJviWDPJ2mTEGxsXT4e4kHRmh" # Replace with your MinIO secret key 97 | BUCKET_NAME = "backup" # Replace with your MinIO bucket name 98 | NUM_FILES = 10 # Number of fake files to generate 99 | 100 | # Run python script for generate fake data and upload to minio. 101 | python script.py 102 | ``` --------------------------------------------------------------------------------