Topics

Solutions

Easy solutions and ideas found after long googling or hard coding

Varnish with secure AWS S3 bucket as backend

Serving static contents from S3 is common, but using Varnish in front is a bit tricky. Especially if you want to keep the bucket secure and only serve from Varnish, here is a simple Varnish file to solve this problem.

First secure your bucket via IP policy:

{
  "Version": "2012-10-17",
  "Id": "S3PolicyId1",
  "Statement": [
    {
      "Sid": "IPAllow",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::example.bucket/*",
      "Condition": {
        "IpAddress": {
          "aws:SourceIp": [
            "5.6.7.8/32"  //varnish ip
          ]
        }
      }
    },
    {
      "Sid": "Explicit deny to ensure requests are allowed only from specific referer.",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::example.bucket/*",
      "Condition": {
        "StringNotLike": {
          "aws:Referer": [
            "https://example.com/*"
          ]
        }
      }
    }
  ]
}

Ansible vault encrypt/decrypt shell script

#!/usr/bin/env bash

####Usage
# ./vault.sh encrypt
# ./vault.sh dencrypt
# ./vault.sh encrypt /full/path/to/file.yml
######

set -euo pipefail

cd `dirname $0`



if [ -z "$PASSWORD" ]; then
    read -s -p "Enter Password: " PASSWORD
fi

VAULT_FILE=vault_key
echo "${PASSWORD}" > "${VAULT_FILE}"

ACTION=decrypt
if [ "$1" != "" ]; then
    ACTION="$1"
fi

FILES=(group_vars/prod/*.yml)
if [ ! -z "${2-}" ]; then
    FILES=("$2")
fi


for FILE in "${FILES[@]}"
do
    if [ "${ACTION}" = "encrypt" ]; then
        echo "Encrypting ${FILE}"
        ansible-vault encrypt "${FILE}.decrypted" --output=$FILE --vault-password-file "${VAULT_FILE}"
    else
        echo "Decrypting ${FILE}"
        ansible-vault decrypt $FILE --output="${FILE}.decrypted" --vault-password-file "${VAULT_FILE}"
    fi
done

rm -rf "${VAULT_FILE}"

Workaround for the slow pagination using skip in MongoDB

Recently I came across a big MongoDB database which needed pagination. But it was surprising how getting to page number 2000 ended up in a timeout. A quick research led me to MongoDB documentation:

The cursor.skip() method is often expensive because it requires the server to walk from the beginning of the collection or index to get the offset or skip position before beginning to return results. As the offset (e.g. pageNumber above) increases, cursor.skip() will become slower and more CPU intensive. With larger collections, cursor.skip() may become IO bound.

So “skip” clearly won’t work for a big set which led to the sort and gt solution.

Sorting and $gt:

Simply sorting by a created_at field then continuing from the last known created_at date by finding the next set would solve the problem.

ids = db.c.find({}, {_id:1}).map(function(item){ return item._id; });
docs = db.c.find( { _id: { $in: ids.slice(2000,2050) } } );

Flash an alert when Jenkins build fails

Jenkins Alert Development teams need to keep track of builds on Jenkins and sometimes an email alert is not flashy enough. Using this simple javascript on your team dashboard you can easily track failed builds and urge developers to fix it.

The script uses Jenkins JSON API with JSONP method to request the latest failed builds with author name and last commit that caused the failure. You will need to add the domain of the page where the request is sent to your “Jenkins” “Configure Global Security” “Domains from which to allow requests” configuration. Also the cookie from Jenkins is needed on the same browser so you will need to login to Jenkins from the same browser before running the script or proxy the request and use Basic Authorization using your API token to do the request.

Demo