Skip to content
> andrew_dryga
Projects
Blitz
Single-handedly owned ~20 high-traffic backends end-to-end (77 Elixir umbrella apps, 70+ Redis/50+ PostgreSQL instances) serving ~25k RPS with peaks to 120k for a 7-figure DAU product.
Firezone
WireGuard-based replacement for legacy VPNs. Re-architected and developed key components of the enterprise product. Led infrastructure as code with Terraform on GCP. Open source, YC W22.
eHealth: National Health Service of Ukraine
Co-designed and built the national platform behind reimbursements, EMR, e-prescriptions, and nationwide APIs for clinics and pharmacies. Led architecture, security, hiring, and hands-on Elixir + DevOps. All development open-sourced under Apache license.
Hammer Corp
Advertising platform for thousands of US automotive dealerships: ingests inventory, syndicates ads to major channels (at peak accountable for 30%+ cars on Facebook Marketplace), measures conversion, and collects leads to a unified interface with 24/7 human first-responder reps answering within 60 seconds.
Bullpen - Virtual Sales Floor + CRM
When COVID hit, our sales team lost the buzz of the office. We built a platform that brought it back - a CRM with virtual space where reps could collaborate, learn from each other in real time, and keep the same drive. Then we turned it into a standalone product with AI sprinkled around it.
TalkInto - Omnichannel Messaging Platform and CRM
Messaging/voice backbone powering products like Hammer, Bullpen, and Text2Buy: SMS, voice, various chat integrations, and web chat with clean agent UI and APIs. Features included local numbers, call recording, and routing.
Contractbook
Built the self-service billing system, B2B API and marketing pipeline that let kicked off the business growt.
Financial P2P Marketplace
Architecture and implementation for an institutional P2P lending marketplace for one of Europe's largest lenders ($9B portfolio).
Mbill - P2P Transfers
P2P transfer service for individuals and small-to-medium online merchants. Create a page for your card and share a link to receive payments. Includes customer cabinet, payment button constructor, and transaction reports.
Mastercard MoneySend
Front-end application to receive P2P transfers sent via recipient phone number. Country-wide rollout of phone-number-based transfers.
Forza - PayDay Loan Websites
Front-end, SMS gateway, decision engine, and marketing tools for an online lending originator operating in Moldova, Bosnia, and North Macedonia.
Best Wallet (ex. MBank)
eWallet cloud for worldwide money transfers. For B2C: pay for 2,700+ services across CIS, send money to phone numbers, cash out via partnered banks or cards. For B2B: free SaaS white-label eWallets for banks with simple integration.
IPSP.com - Payment Pages
Responsive landing and payment pages for an Internet Payment Service Provider. Improved conversion on payment flows via lighter UI.
ECommPay - Mobile App
iOS and Android business application for partners to manage payment platform on the go.
Autopayment
Automatically pays for bills based on two types of rules: by threshold of supplier balance (e.g., mobile top-up) or on a periodic basis.
Mobile Cashier
Turns Android devices into payment terminals for deposits and top-ups across numerous service providers, from cellular carriers to credit card loan repayments.
Sage - Sagas Pattern in Elixir
Dependency-free implementation of the Sagas pattern for distributed transactions with explicit compensation. Guarantees that either all transactions complete successfully, or compensating transactions amend partial execution.
LoggerJSON
Structured JSON logging for Elixir with first-class formatters for Google Cloud Logging, Datadog, and Elastic (ECS). Drop-in :logger formatter/handler with runtime config helpers.
Confex
Runtime configuration from environment variables with type casting and adapters (:system, :system_file). 12-factor friendly configuration for Elixir applications.
Elixir Bench
Continuous benchmarking platform for the Elixir ecosystem. Automatically runs performance benchmarks on each commit to detect regressions and track language performance improvements over time. Won Spawnfest 2017 and later accepted into Google Summer of Code.
Annon API Gateway
Configurable API gateway acting as a reverse proxy with a plugin system (ACL, Auth, Validation, CORS, Idempotency), request/response storage, metrics, management UI, and auth provider. Reduces boilerplate across services.
Ecto Mnesia Adapter
Ecto adapter for OTP's built-in Mnesia database that works in the same memory space as the application, providing extremely low latency without deploying a separate database.
Gandalf - Decision Engine
Open-source decision engine SaaS for rule tables, champion/challenger split testing, revision history, decision analytics, and debugging tools.
Man - Template Rendering Engine
Stores iex, mustache, or markdown templates and renders them with localization to HTML or PDF via REST JSON API. Includes an easy-to-use management UI. Free one-click deployment to Heroku.
Vagrant Box OS X
macOS Vagrant boxes for VirtualBox. Run UX tests or build iOS/Mac applications on any machine with a few CLI commands. Used by many teams worldwide, including Boxen.
Parasport - Foundation Portal
Medium-sized web portal for a foundation supporting Paralympic sport, physical rehabilitation, and social adaptation. Built on October CMS.
OneDayOfMine
Storytelling social network that helps see other people's lives through their eyes. Capture moments through the day and share them with descriptions - from special forces in Belarus to a family visit to a film museum in South Korea.
L15 - Night Club x Coworking
Experimental mix of coworking space and a night club ('clubworking') in Kyiv. Turned the office into a best-in-class night club and ran terrace events with world-class DJs every weekend for an entire summer.
Happy Customer
Outsource project to motivate small and medium-sized businesses to provide better customer service via public feedback and simple tracking.
truBrain 1.0
An early-stage product that needed help. I took some swings at UX and performance for free because I wanted to see them make it.
Blog
The Real 10x Engineer
The real multiplier in software isn’t writing more code. It’s judgment: choosing the right problems, avoiding unnecessary systems, and reducing the maintenance burden that slows teams down.
Introducing Sage - a Sagas pattern implementation in Elixir
Distributed transactions are hard and expensive, if you wonder how to pragmatically handle them in a mid-size project - this article is for you.
Run stale tests on file change in Elixir
Mix is an awesome tool but most Elixir beginners are not aware of all its features. mix test --stale is one of them and can make your workflow much better.
Runtime configuration, migrations and deployment for Elixir applications
Shortly after moving from PHP to Elixir I've faced a common issue, the way how do we deploy applications is totally different from the one I'm used to.
National Health Service, on Elixir and Kubernetes
A look at building Ukraine’s national-scale eHealth platform with Elixir, Kubernetes, and pragmatic architecture for reliability and scale.
Bringing blockchain properties to centralized government databases
Making it cryptographically impossible to alter records in a database even with full system access.
Alternative approach for sensitive file uploads
Using signed URLs for secure file uploads directly to cloud storage, bypassing your application servers entirely.
Designing a P2P Lending platform with Elixir in mind
With this post, I want to share with you the design process on one of our latest projects - a P2P marketplace that was intended to be used by hundreds of thousands of users.
$ cat ./blog/sensitive-file-uploads

Alternative approach for sensitive file uploads.

While working on a new project we faced a task where end-user needs to upload a file with the sensitive data (eg. national ID of most people in a country, yay), which should be persisted within a minimal security perimeter.

I do not think that this is the only right approach, there is always a tradeoff. This solution was the best for our use case.

Picking the data store

Since we are running our projects on Google Container Engine, we decided to keep using benefits of cloud services and store files in Google Cloud Storage. There is no real vendor lock addition because of it, there are plenty of similar solutions that can replace existing implementation by only rewriting the API connector: Amazon S3, OpenStack Swift and even some containerized open source solutions with compatible APIs.

When you deploy to Kubernetes you have an additional benefit by using cloud storages - you don’t need to deal with persistent volumes and backups for the data.

And a security benefit is that cloud storage guarantees that there is no way to perform Unrestricted File Upload to Remote Code Execution attacks, which PayPal faced recently.

What is the common approach for handling uploads?

Most projects I’ve seen take a simple approach where API consumers upload files directly to the application, which uses libraries like arc to take care of future file processing and storing it in an upstream storage.

Client
Application
Cloud Storage
Upload file
Process file
Store file
OK
OK
The common approach

The main advantage of it is that it is simple to understand and provides ability synchronously post process the data - crop the image, validate its mime-type, contents, etc and respond immediately to a client.

But what are the disadvantages:

  • Sensitive data is temporarily stored in the application, which extends security perimeters. It can be intercepted, accidentally persisted along with a VM snapshot, you can simply forget to remove temporary copies. This problem is magnified in microservice architectures, where those requests hit multiple application services;
  • You can run out of disk space while processing large uploads;
  • Increased RAM usage, some API clients are not able to perform chunk uploads;
  • Credentials for cloud storage are long-living. More credential lives, less secure it is because the probability of leaking it grows over time. In monolith, any parts of the code can use them. Any microservice that works with these files needs a copy or a separate service account.

Can we do better?

Signed URL’s

Most of the cloud storage providers (1, 2, 3) allow signing a URL that can be used as temporary access token to send a file directly to the cloud storage. This URL can grant only a fraction of what application IAM role allows, limiting to only a single file upload within a limited time frame.

IAM role itself can allow only write access, thus even by holding a service account private key, it is not possible to read data from the storage.

Client
Application
Cloud Storage
Request upload URL
Generate signed URL
Signed URL
Upload file directly
OK
Upload with a Signed URL

There are plenty of options for how to run post-processing for uploads:

  • Spin up a worker GenServer with a delayed message and timeout greater than signed URL TTL;
  • Depending on your storage provider you might also be able to define a callback (eg. with AWS lambda or Google Cloud pub/sub) that triggers file processing pipeline in your back-end;
  • Or make your front-end responsible for notifying on successful file upload by posting related metadata to the back-end, as we did.
Client
Application
Queue
Worker
Cloud Storage
File uploaded, here's metadata
Queue processing job
Process file
Fetch file
File data
Post-process
Done
Async job processing

Do not go this direction when you have a monolith, without an isolated microservice your application would still share a secret with full bucket permissions and it would be meaningless in terms of security.

Also, it negates most of the performance benefits we discussed above, but allows to queue jobs and spend this time asynchronously which requires us to have fewer resources up and running.

Secret management for Cloud Storage

We took one more step further and built a Cloud Storage secret management around this idea. Similarly to Hashicorp Vault, each time some part of our application or a front-end (that verifies document contents) needs an access to the file in storage, it requests a Signed URL with only the rights that it needs and a reasonable TTL.

Client
Application
Secret Manager
Cloud Storage
Request file access
Request signed URL
Authorize & log request
Generate signed URL
Signed URL
Signed URL
Fetch file with signed URL
File data
Working via Storage Secret Manager

These requests can be authorized based on service role and logged for a security trail.

Implementation

Erlang/OTP has a :public_key application to handle public-key infrastructure, building and signing URL takes only a few lines of code:

defmodule Ael.Secrets.API do
  def get_secret_url(secret) do
    %Secret{
      action: action, 
      expires_at: expires_at, 
      bucket: bucket, 
      resource_id: resource_id, 
      resource_name: resource_name
    } = secret

    canonicalized_resource = "/#{bucket}/#{resource_id}/#{resource_name}"
    signature =
      action
      |> string_to_sign(expires_at, canonicalized_resource)
      |> sign()
      |> Base.encode64()
      |> URI.encode_www_form()

    "https://storage.googleapis.com#{canonicalized_resource}" <>
    "?GoogleAccessId=#{get_from_registry(:gcs_service_account_id)}" <>
    "&Expires=#{expires_at}" <>
    "&Signature=#{signature}"
  end

  defp string_to_sign(action, expires_at, canonicalized_resource), 
    do: Enum.join([action, "", "", expires_at, canonicalized_resource], "\n")

  defp sign(plaintext),
    do: :public_key.sign(plaintext, :sha256, get_from_registry(:gcs_service_account_key))

  defp get_from_registry(key) do
    [{_pid, val}] = Registry.lookup(Ael.Registry, key)
    val
  end
end

Full source code is available in a GitHub repo, it is a dockerized Phoenix 1.3 microservice: Nebo15/ael.api

Thanks

I want to thank Pavel Vesnin who was responsible for most of the implementation code.

Related Projects

eHealth: National Health Service of Ukraine

Co-designed and built the national platform behind reimbursements, EMR, e-prescriptions, and nationwide APIs for clinics and pharmacies. Led architecture, security, hiring, and hands-on Elixir + DevOps. All development open-sourced under Apache license.

View project →
Projects
Blitz
Single-handedly owned ~20 high-traffic backends end-to-end (77 Elixir umbrella apps, 70+ Redis/50+ PostgreSQL instances) serving ~25k RPS with peaks to 120k for a 7-figure DAU product.
Firezone
WireGuard-based replacement for legacy VPNs. Re-architected and developed key components of the enterprise product. Led infrastructure as code with Terraform on GCP. Open source, YC W22.
eHealth: National Health Service of Ukraine
Co-designed and built the national platform behind reimbursements, EMR, e-prescriptions, and nationwide APIs for clinics and pharmacies. Led architecture, security, hiring, and hands-on Elixir + DevOps. All development open-sourced under Apache license.
Hammer Corp
Advertising platform for thousands of US automotive dealerships: ingests inventory, syndicates ads to major channels (at peak accountable for 30%+ cars on Facebook Marketplace), measures conversion, and collects leads to a unified interface with 24/7 human first-responder reps answering within 60 seconds.
Bullpen - Virtual Sales Floor + CRM
When COVID hit, our sales team lost the buzz of the office. We built a platform that brought it back - a CRM with virtual space where reps could collaborate, learn from each other in real time, and keep the same drive. Then we turned it into a standalone product with AI sprinkled around it.
TalkInto - Omnichannel Messaging Platform and CRM
Messaging/voice backbone powering products like Hammer, Bullpen, and Text2Buy: SMS, voice, various chat integrations, and web chat with clean agent UI and APIs. Features included local numbers, call recording, and routing.
Contractbook
Built the self-service billing system, B2B API and marketing pipeline that let kicked off the business growt.
Financial P2P Marketplace
Architecture and implementation for an institutional P2P lending marketplace for one of Europe's largest lenders ($9B portfolio).
Mbill - P2P Transfers
P2P transfer service for individuals and small-to-medium online merchants. Create a page for your card and share a link to receive payments. Includes customer cabinet, payment button constructor, and transaction reports.
Mastercard MoneySend
Front-end application to receive P2P transfers sent via recipient phone number. Country-wide rollout of phone-number-based transfers.
Forza - PayDay Loan Websites
Front-end, SMS gateway, decision engine, and marketing tools for an online lending originator operating in Moldova, Bosnia, and North Macedonia.
Best Wallet (ex. MBank)
eWallet cloud for worldwide money transfers. For B2C: pay for 2,700+ services across CIS, send money to phone numbers, cash out via partnered banks or cards. For B2B: free SaaS white-label eWallets for banks with simple integration.
IPSP.com - Payment Pages
Responsive landing and payment pages for an Internet Payment Service Provider. Improved conversion on payment flows via lighter UI.
ECommPay - Mobile App
iOS and Android business application for partners to manage payment platform on the go.
Autopayment
Automatically pays for bills based on two types of rules: by threshold of supplier balance (e.g., mobile top-up) or on a periodic basis.
Mobile Cashier
Turns Android devices into payment terminals for deposits and top-ups across numerous service providers, from cellular carriers to credit card loan repayments.
Sage - Sagas Pattern in Elixir
Dependency-free implementation of the Sagas pattern for distributed transactions with explicit compensation. Guarantees that either all transactions complete successfully, or compensating transactions amend partial execution.
LoggerJSON
Structured JSON logging for Elixir with first-class formatters for Google Cloud Logging, Datadog, and Elastic (ECS). Drop-in :logger formatter/handler with runtime config helpers.
Confex
Runtime configuration from environment variables with type casting and adapters (:system, :system_file). 12-factor friendly configuration for Elixir applications.
Elixir Bench
Continuous benchmarking platform for the Elixir ecosystem. Automatically runs performance benchmarks on each commit to detect regressions and track language performance improvements over time. Won Spawnfest 2017 and later accepted into Google Summer of Code.
Annon API Gateway
Configurable API gateway acting as a reverse proxy with a plugin system (ACL, Auth, Validation, CORS, Idempotency), request/response storage, metrics, management UI, and auth provider. Reduces boilerplate across services.
Ecto Mnesia Adapter
Ecto adapter for OTP's built-in Mnesia database that works in the same memory space as the application, providing extremely low latency without deploying a separate database.
Gandalf - Decision Engine
Open-source decision engine SaaS for rule tables, champion/challenger split testing, revision history, decision analytics, and debugging tools.
Man - Template Rendering Engine
Stores iex, mustache, or markdown templates and renders them with localization to HTML or PDF via REST JSON API. Includes an easy-to-use management UI. Free one-click deployment to Heroku.
Vagrant Box OS X
macOS Vagrant boxes for VirtualBox. Run UX tests or build iOS/Mac applications on any machine with a few CLI commands. Used by many teams worldwide, including Boxen.
Parasport - Foundation Portal
Medium-sized web portal for a foundation supporting Paralympic sport, physical rehabilitation, and social adaptation. Built on October CMS.
OneDayOfMine
Storytelling social network that helps see other people's lives through their eyes. Capture moments through the day and share them with descriptions - from special forces in Belarus to a family visit to a film museum in South Korea.
L15 - Night Club x Coworking
Experimental mix of coworking space and a night club ('clubworking') in Kyiv. Turned the office into a best-in-class night club and ran terrace events with world-class DJs every weekend for an entire summer.
Happy Customer
Outsource project to motivate small and medium-sized businesses to provide better customer service via public feedback and simple tracking.
truBrain 1.0
An early-stage product that needed help. I took some swings at UX and performance for free because I wanted to see them make it.
Blog
The Real 10x Engineer
The real multiplier in software isn’t writing more code. It’s judgment: choosing the right problems, avoiding unnecessary systems, and reducing the maintenance burden that slows teams down.
Introducing Sage - a Sagas pattern implementation in Elixir
Distributed transactions are hard and expensive, if you wonder how to pragmatically handle them in a mid-size project - this article is for you.
Run stale tests on file change in Elixir
Mix is an awesome tool but most Elixir beginners are not aware of all its features. mix test --stale is one of them and can make your workflow much better.
Runtime configuration, migrations and deployment for Elixir applications
Shortly after moving from PHP to Elixir I've faced a common issue, the way how do we deploy applications is totally different from the one I'm used to.
National Health Service, on Elixir and Kubernetes
A look at building Ukraine’s national-scale eHealth platform with Elixir, Kubernetes, and pragmatic architecture for reliability and scale.
Bringing blockchain properties to centralized government databases
Making it cryptographically impossible to alter records in a database even with full system access.
Alternative approach for sensitive file uploads
Using signed URLs for secure file uploads directly to cloud storage, bypassing your application servers entirely.
Designing a P2P Lending platform with Elixir in mind
With this post, I want to share with you the design process on one of our latest projects - a P2P marketplace that was intended to be used by hundreds of thousands of users.