This application allows users to vote once per poll, with encrypted vote storage and admin management, including poll creation and expiration logic.
Backend:
- Flask (Python Web Framework)
- SQLAlchemy (ORM)
- Flask-Login (Authentication)
- Flask-WTF (CSRF Protection)
- Gunicorn (WSGI Server)
Security:
- Fernet Encryption (Vote Privacy)
- CSRF Protection
- Password Hashing (Werkzeug)
- Blockchain-style Vote Ledger
DevOps:
- Docker & Docker Compose
- Kubernetes-ready
- Volume-based Persistence
- Health Check Endpoints
| Feature | Status |
|---|---|
| Create polls (admin only) | ✅ |
| Vote once per poll (browser cookie & hash check) | ✅ |
| SQLAlchemy database model (SQLite volume) | ✅ |
| Encrypted voting using Fernet | ✅ |
| Secret stored outside codebase | ✅ |
| Key changes when container is re-created(unless same volumes are used) | ✅ |
| WSGI (Gunicorn) for production | ✅ |
| Docker & Docker Compose setup | ✅ |
| Kubernetes-ready deployment flow | ✅ |
poll_app/
│
├── app.py
├── wsgi.py
├── models.py
├── utils.py
├── admin.py
├── poll_blueprint.py
├── requirements.txt
├── entrypoint.sh
├── Dockerfile
├── docker-compose.yml
├── gunicorn.conf.py
│
├── templates/
├── static/
│
└── data/ (Docker volume mount)
├── poll_encryption_key
├── polls.db
└── ledger.jsonl
Votes are encrypted using Fernet symmetric encryption.
The encryption key:
- Is not stored in code
- Is mounted at runtime via secrets
- Can rotate safely if using MultiFernet mode
Users can vote only once using:
- Browser cookie identifier
- Optional secondary validation (e.g., hashed IP or session-tied signature)
Admin credentials are set through environment variables:
ADMINU=admin
ADMINP=adminpass
python -m venv venv
source venv/bin/activate
pip install -r requirements.txtFor local development, create a data directory:
mkdir -p data
python - <<EOF
from cryptography.fernet import Fernet
with open('data/poll_encryption_key', 'wb') as f:
f.write(Fernet.generate_key())
EOFNote: When running with Docker, this is handled automatically by entrypoint.sh
docker-compose up --buildApp runs at:
- SQLite DB stored in a Docker volume
- Encryption key stored in mounted in same volume
- Uses python:3.11-slim
- Runs under Gunicorn WSGI
entrypoint.shcreates or loads the encryption key and makes admin
On first run:
- Generates a new encryption key and admin account
- Saves it to mounted secret path
On subsequent restarts:
- Reuses the persisted key
- same volumes use same key due to reusability
This supports:
| Deployment | Result |
|---|---|
| Restart Same container with same volume | Same key retained |
| Restart new container same volume | Same key retained |
| Restart with new volume | New key generated |
Workflow:
- Push image to registry
- Create Kubernetes Secret:
kubectl create secret generic poll-encryption-key \
--from-file=poll_encryption_key=secrets/poll_encryption_key- Apply Deployment + PVC + Service
- Expose via Ingress + HTTPS
| Variable | Purpose |
|---|---|
SECRET_KEY |
Flask session secret key |
ADMINU |
Built-in admin username |
ADMINP |
Built-in admin password |
FLASK_ENV |
development / production |
POLL_ENCRYPTION_KEY |
(Optional) Encryption key |
Application entry point is:
wsgi:app
This makes the app compatible with:
- Gunicorn
- uWSGI
- Nginx reverse proxy stacks
Flask
Flask-SQLAlchemy
Flask-Login
Flask-Migrate
cryptography
Flask-WTF
WTForms
python-dotenv
gunicorn
- Fork
- Create feature branch
- Submit Pull Request
PRs should follow:
- Secure coding practices
- Stateless container principles
- Configurable secrets — never committed keys
- Check Docker logs:
docker-compose logs -f - Ensure
/datadirectory has proper permissions - Verify environment variables are set
- Check
ADMINUandADMINPenvironment variables - Remove
/data/admin_createdto recreate admin:docker-compose exec poll-app rm /data/admin_created - Restart container:
docker-compose restart
- Check if encryption key exists:
docker-compose exec poll-app ls -la /data/poll_encryption_key - Verify file permissions on
/datadirectory
- Reset database: change volume(because databse is stored in it) and re-create container
docker-compose up --buildOpen your browser to http://localhost:5000
- Username:
admin(or whatever you set inADMINU) - Password:
adminpass(or whatever you set inADMINP)
- Click "Admin Dashboard"
- Click "Create New Poll"
- Enter question and options
- Set start/end times (optional)
- Click "Create Poll"
- Navigate to homepage
- Click on a poll
- Select your choice
- Submit vote
MIT License
Built and iterated via architectural planning including:
- Encryption key security best practices
- Dockerized deployment
- Kubernetes-ready secret management
- Poll expiration logic
- Secure one-vote enforcement
Ready to deploy. Secure by design. Cloud-scalable.


