Generate Custom SSH Keys for Developers on Your Amazon Instances

The process is pretty simple. Let’s say you use an ssh key (.pem) file generated by Amazon. However you use the same key on a few of your instances and you’d like to allow a developer access to only one at a time.

To do that, you need to generate a custom ssh key for your developer to log into one machine:

  1. Generate a custom ssh key (private)
  2. Generate a public key
  3. Change permissions of the folders and ssh keys container the newly generated keys on both your machine and server
  4. Copy the public key to the target ssh key
#private key
openssl genrsa -des3 -out MyKey.pem
#public key
ssh-keygen -y -f MyKey.pem > abc.pub
#permissions
chmod 400 MyKey.pem
chmod 700 .ssh
chmod 600 .ssh/authorized_keys -> server side
#copy to server
copy the public key to .ssh/authorized_keys -> server side

That’s it! You should end up with keys that your developer can use on only the servers you allow.

Get the most recent commit hash

Sometimes you just need one line that says your most recent commit in git. You just want to make sure everything is up to date. It’s super simps.

git rev-parse HEAD

Dali Museum

What if you could “Dali-ize” yourself into a work of art? This was the concept behind Gala Contemplating You, where Salvador Dali’s famous work of art turns the viewer into a painting. The concept is simple, take a picture of yourself and we’ll turn you into a one of a kind digital work of art. Shortly thereafter, we show you in the Salvador Dali Museum, next to the real thing for the world to see!

A photo kiosk at the Museum turned visitors’ self-portraits into pixelated replications of the original artwork and projects these new images alongside the original monumental canvas. A corresponding mobile website (galacontemplatingyou.com) allowed virtual visitors – from anywhere around the globe – to submit their photos and become part of the artwork as well. Once displayed, a photo of your work of art next to the original is automatically shared back to you, closing the loop.

We had over 19k submissions gained a ton of press about the project as well as the museum.

The Team

We had a good team for this project. Kia produced the software that controlled the camera mounted in the museum. Marpi, produced the software that controlled the projections and helped with installation. Chris and Pablo had the concept. Patrick and MBK kept us all in check by managing the project.

My Role

Production of the backend, mobile app and in-museum photo kiosk.

Technologies

  • In-museum photo kiosk
    • Objective-C: native iPad app to do initial scaling/adjustment of images & submit the to the backend through an API
  • Server
    • JavaScript: Amazon Ec2 instance running NodeJS, Amazon S3 for media storage and Amazon RDS for database
  • Mobile App
    • HTML5 + CSS3: mobile app allowing users to capture & upload images from anywhere

 

How to Open a New Window From Menu Cocoa

quick one today.

The video shows you how to open a new nswindow from a drop down menu selection. It allows for the nib to be instantiated and call all of the expected “windowDidLoad” behavior.

 

8 Bit Color or 256 Color Array

I’m sending color to an arduino and I’d like to send the entire rgb value in one byte. It’s easy to translate this from rgb values. Something like:

int color = ((b&255 & 0xC0)+((g&255 & 0xE0) >> 2)+((r & 0xE0) >> 5))&0xFF;

But once you get that byte to the arduino, you need to convert it back to an RGB value if you are doing anything useful with neopixels or whatever, so here’s the conversion chart. The keys are the number corresponding to the 8 bit color (0-255):

["0,0,0",
 "35,0,1",
 "71,1,2",
 "107,2,6",
 "142,4,10",
 "178,6,16",
 "214,9,21",
 "249,13,27",
 "1,35,2",
 "36,36,2",
 "71,36,4",
 "107,36,7",
 "142,37,12",
 "178,38,17",
 "214,39,22",
 "249,40,28",
 "5,71,6",
 "37,71,6",
 "72,71,8",
 "107,72,11",
 "143,72,15",
 "178,72,20",
 "214,73,24",
 "249,73,30",
 "11,107,13",
 "39,107,14",
 "73,107,15",
 "108,107,18",
 "143,107,21",
 "179,108,24",
 "214,108,28",
 "250,108,33",
 "18,143,22",
 "42,143,22",
 "75,143,23",
 "109,143,24",
 "144,143,27",
 "179,143,30",
 "214,143,33",
 "250,143,37",
 "26,178,30",
 "46,178,30",
 "77,178,31",
 "110,178,32",
 "145,178,34",
 "180,179,36",
 "215,179,39",
 "250,179,42",
 "undefined",
 "51,214,38",
 "79,214,39",
 "112,214,40",
 "146,214,41",
 "181,214,43",
 "216,214,46",
 "251,214,48",
 "undefined",
 "56,250,46",
 "82,250,46",
 "114,250,47",
 "147,250,49",
 "182,250,50",
 "217,250,52",
 "252,250,55",
 "1,5,83",
 "36,6,83",
 "71,6,84",
 "107,7,84",
 "142,9,85",
 "178,11,86",
 "214,14,87",
 "249,17,88",
 "2,37,84",
 "36,37,84",
 "71,38,84",
 "107,38,84",
 "142,39,85",
 "178,39,86",
 "214,40,87",
 "249,42,88",
 "6,72,84",
 "37,72,84",
 "72,72,85",
 "107,72,85",
 "143,73,86",
 "178,73,87",
 "214,74,88",
 "249,74,89",
 "12,107,85",
 "40,107,85",
 "73,108,86",
 "108,108,86",
 "143,108,87",
 "179,108,88",
 "214,108,89",
 "250,109,90",
 "19,143,87",
 "43,143,87",
 "75,143,87",
 "109,143,88",
 "144,143,88",
 "179,143,89",
 "214,144,90",
 "250,144,92",
 "26,179,89",
 "46,179,89",
 "77,179,89",
 "110,179,90",
 "145,179,90",
 "180,179,91",
 "215,179,92",
 "250,179,94",
 "undefined",
 "51,214,92",
 "79,214,92",
 "112,214,92",
 "146,214,93",
 "181,214,94",
 "216,215,95",
 "251,215,96",
 "undefined",
 "56,250,95",
 "82,250,95",
 "114,250,96",
 "148,250,96",
 "182,250,97",
 "217,250,98",
 "252,250,99",
 "4,20,167",
 "37,20,167",
 "72,21,167",
 "107,21,167",
 "143,22,168",
 "178,24,168",
 "214,25,168",
 "249,27,169",
 "6,43,167",
 "37,43,167",
 "72,43,167",
 "107,44,167",
 "143,44,168",
 "178,45,168",
 "214,46,169",
 "249,47,169",
 "9,75,167",
 "39,75,167",
 "73,75,167",
 "108,75,168",
 "143,76,168",
 "178,76,168",
 "214,77,169",
 "249,77,169",
 "15,109,168",
 "41,109,168",
 "74,109,168",
 "108,109,168",
 "143,110,168",
 "179,110,169",
 "214,110,169",
 "250,111,170",
 "21,144,169",
 "44,144,169",
 "75,144,169",
 "109,144,169",
 "144,145,169",
 "179,145,169",
 "215,145,170",
 "250,145,171",
 "28,180,169",
 "47,180,169",
 "77,180,170",
 "111,180,170",
 "145,180,170",
 "180,180,170",
 "215,180,171",
 "251,180,172",
 "undefined",
 "52,215,171",
 "80,215,171",
 "112,215,171",
 "146,215,171",
 "181,215,172",
 "216,215,172",
 "251,215,173",
 "undefined",
 "57,250,172",
 "83,250,172",
 "114,250,173",
 "148,251,173",
 "182,251,173",
 "217,251,174",
 "252,251,174",
 "undefined",
 "undefined",
 "undefined",
 "undefined",
 "undefined",
 "undefined",
 "undefined",
 "undefined",
 "12,52,251",
 "40,52,251",
 "73,53,251",
 "108,53,251",
 "143,53,251",
 "179,54,251",
 "214,54,252",
 "250,55,252",
 "15,80,251",
 "41,80,251",
 "74,80,251",
 "108,81,251",
 "143,81,251",
 "179,81,251",
 "214,82,252",
 "250,82,252",
 "19,113,251",
 "43,113,251",
 "75,113,251",
 "109,113,251",
 "144,113,251",
 "179,113,252",
 "214,114,252",
 "250,114,252",
 "25,147,252",
 "45,147,252",
 "76,147,252",
 "110,147,252",
 "145,147,252",
 "180,147,252",
 "215,147,252",
 "250,148,253",
 "31,181,252",
 "49,181,252",
 "78,181,252",
 "111,181,252",
 "146,182,252",
 "180,182,253",
 "215,182,253",
 "251,182,253",
 "undefined",
 "53,216,253",
 "81,216,253",
 "113,216,253",
 "147,217,253",
 "181,217,253",
 "216,217,254",
 "251,217,254",
 "undefined",
 "58,252,254",
 "84,252,254",
 "115,252,254",
 "148,252,254",
 "182,252,254",
 "217,252,255",
 "255,255,255"]

xCode Can’t Drag IBOutlets or IBActions

Sometimes life is simple, too simple.

Sometimes you get stuck for a day and it was something totally ridiculous that you couldn’t figure out. This is one of those days.

Doing IOS Development, I thought I had it down. Create a new UIView, create a new view controller class, and set the UIViewController’s class to the newly created class in the interface builder.

Not so with Cocoa and native development. Don’t worry Apple makes it just as easy. Have a look:

 

Amazon RDS Creating Functions in MySQL

Had a problem creating functions in MySQL with the standard user for an RDS instance on Amazon.

For those who don’t know, Amazon RDS is a sweet place to host a remote database, kind of expensive but worth it if you are using a distributed system. Anyway…

The problem is when you try to run something like:

DROP FUNCTION IF EXISTS hello_world;
DELIMITER $$
CREATE FUNCTION hello_world(addressee TEXT)
  RETURNS TEXT
  DETERMINISTIC
  READS SQL DATA
  LANGUAGE SQL -- This element is optional and will be omitted from subsequent examples
BEGIN
  RETURN CONCAT('Hello ', addressee);
END;
$$
DELIMITER ;

SELECT hello_world('Earth');

You get an error message saying something like:

“ERROR 1419: You do not have the SUPER privilege and binary logging is enabled”

This is because the sql server is not accepting incoming create requests from a SUPER

To fix this is not so straight forward. Basically, the solution is here. You need to fix the problem by relaxing the “trust function creators” pool in the parameters.

  1. Go to your amazon RDS portal and select “Parameter Groups” from the left hand menu
  2. Create a new group and name it whatever you want, also put the description to whatever you want
  3. Now select that group and click “Edit Parameters”
  4. Look for the parameter called “log_bin_trust_function_creators” and set it to 1 in the drop down menu
  5. Now you can go back to your instances and select the instance that you want to apply the new settings to.
  6. In your “instance actions” select to modify
  7. Now set your parameters group to the new group and make sure you apply changes immediately
  8. Press “continue” and wait for everything to be updated (or say “pending reboot”), then reboot your rds instance

That should be it, you should be able to run the above function on MySQL 5.5+ no prob bob

 

Add SSL to EC2 Instance

You want https on your ec2 instance with nodejs? easy.

First thing is first. There are new rules. You can’t get an ssl certificate anymore that assignes to an IP address (More here). If you don’t know what this means, don’t worry about it. I’ll walk your through.

You’re going to need to set a few things up.

  1. First, set up a new instance on EC2 (make sure in your security group you open port 443  to “0.0.0.0/0”).
  2. Then associate an elastic IP address.
  3. Once you have this, go to your favorite registrar and buy a domain. If you already have one, that’s fine. Make sure you know what’s on your whois information. You’re going to need to apply for an ssl cert with the same contact information.
  4. Point the domain at your IP address:

Once you have your domain associate to the elastic IP address you can start applying for the ssl cert.

Now it’s time to grab openSSL and make a certificate request. To generate one, take a look at the documentation here: http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/configuring-https.html#configuring-https-ssl-rsa.

  1. Download openSSL: https://www.openssl.org/source/ or type the following command in your terminal:
  2. which openssl

    * if you see a path to openssl then you already have it installed on your computer. For instance mine was installed automatically when I installed XAMPP.

  3. You need to first generate your private key:
  4. cd /path/to/directory/where/you/want/to/store/your/certs
    openssl genrsa 2048 > privatekey.pem
  5. Now you want to generate your certificate signing request. Make sure you follow the instructions linked to above:
  6. openssl req -new -key privatekey.pem -out csr.pem
  7. You will be prompted to fill in some contact information, make sure this is correct so they can verify it’s actually you. This information will be checked against the whois record for your domain, so make sure the information you put in here, matches the whois.
  8. * Also, for the common name (CA) make sure you use the domain name you pointed at your elastic IP, not the IP itself. You will get rejected otherwise. An example might be: “mydomain.com” not”54.204.243.234″ or “http://mydomain.com/”

  9. At this point you can buy an ssl cert. Make sure you buy a domain verification cert if you are looking for the cheapest route. Many will try to sell you extended verification certs. These can take a week to validate because they check your business out as well. Domain certs only take a couple of minutes, they verify that the whois matches and they can reach your server. Then they issue the cert.
  10. At this point you’re done. You can generate a temporary self signed cert if you want to test locally. Just enter your local information instead and do:
  11. openssl x509 -req -days 365 -in csr.pem -signkey privatekey.pem -out server.crt

Now that you have your cert (most like you received a zip folder with multiple certs) what do you do?

I’m running NodeJS and this is how I did it:

  1. put the certs in a folder that my nodeJS process can find.
  2. Add the following using express to my head:
  3. var express = require('express'),
        fs = require('fs'),
        https = require('https'),
        config = require('./config');
  4. Then this to my setup:
  5. var options = {
        key: fs.readFileSync(config.sslKeyPath),
        cert: fs.readFileSync(config.sslCertPath)
    };
    
    if(config.environment != 'local') {
        console.log('adding ca cert')
        options.ca = [fs.readFileSync(config.sslCaPath)];
    }
    
    var app = express();
    
    var server = https.createServer(options, app);
    
    server.listen(config.sslSocketPort, function() {
        console.log("Listening on " + config.sslSocketPort);
    });
    
    // if you are using ws or something like it, add the server
    var wss = new WebSocketServer({server: server});
  6. I have  a separate config file with the following structure:
  7. var config = {}
    
    // environmentals
    config.environment = process.env.DEVELOPMENT_ENVIRONMENT;
    
    if(config.environment == 'local') {
        config.sslSocketPort = 5053;
    
        config.sslKeyPath = '/Applications/XAMPP/xamppfiles/htdocs/path/to/privatekey.pem';
        config.sslCaPath = '/Applications/XAMPP/xamppfiles/htdocs/path/to/gd_bundle-g2-g1.crt';
        config.sslCertPath = '/Applications/XAMPP/xamppfiles/htdocs/path/to/server.crt';
    } else {
        config.sslSocketPort = 443;
    
        config.sslKeyPath = '/home/ubuntu/path/to/privatekey.pem';
        config.sslCaPath = '/home/ubuntu/path/to/gd_bundle-g2-g1.crt';
        config.sslCertPath = '/home/ubuntu/path/to/0a87sgdf087asdfg.crt';
    }
    
    module.exports = config;
  8. Then I set a .env file on my local and my remote server. The local has this in it:
  9. DEVELOPMENT_ENVIRONMENT=local
  10. The remote has:
  11. DEVELOPMENT_ENVIRONMENT=remote

This way the config file can tell whether I’m running locally or remotely.

That’s it! Basically all that config shit you can figure out on your own, just wanted to include so I don’t confuse people.