<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[The Chicken Coop]]></title><description><![CDATA[C# and iOS Development. AWS and SRE. Tequila, Coffee, Tacos and Chocolate. What else is there, really?]]></description><link>https://fastchicken.co.nz/</link><image><url>https://fastchicken.co.nz/favicon.png</url><title>The Chicken Coop</title><link>https://fastchicken.co.nz/</link></image><generator>Ghost 3.1</generator><lastBuildDate>Tue, 17 Dec 2019 09:17:54 GMT</lastBuildDate><atom:link href="https://fastchicken.co.nz/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Shut the back door - Locking an AWS ALB to CloudFront]]></title><description><![CDATA[<p>A common way to use AWS CloudFront is to use it as the front end for an Application Load Balancer. You would normally set it up as so:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/11/cloudfront-waf-crop.png" class="kg-image"><figcaption>Person talks to CloudFront talks to ALB talks to Containers/Backend</figcaption></figure><p>CloudFront is doing the perimeter work, including caching and WAF, which</p>]]></description><link>https://fastchicken.co.nz/2019/11/20/shut-the-back-door-locking-an-aws-alb-to-cloudfront/</link><guid isPermaLink="false">5dd58305857fc30001873bce</guid><dc:creator><![CDATA[Nic Wise]]></dc:creator><pubDate>Wed, 20 Nov 2019 20:20:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1563205237-1954f86b0f16?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1563205237-1954f86b0f16?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=2000&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Shut the back door - Locking an AWS ALB to CloudFront"><p>A common way to use AWS CloudFront is to use it as the front end for an Application Load Balancer. You would normally set it up as so:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/11/cloudfront-waf-crop.png" class="kg-image" alt="Shut the back door - Locking an AWS ALB to CloudFront"><figcaption>Person talks to CloudFront talks to ALB talks to Containers/Backend</figcaption></figure><p>CloudFront is doing the perimeter work, including caching and WAF, which it then passes to the Origin - the ALB - which distributes it to the back end, in this case, a set of containers.</p><p>However, there is nothing stopping someone scanning the AWS IP space, connecting to every IP on port 80 and 443 to see what they can find. If they find your server, they would have bypassed the WAF, circumventing SQL Injection and Cross Site Scripting protection amongst other features. This is usually something you want to avoid.</p><p>We recently implemented one of the techniques below, with logging, and it was surprising how much of this happens in the “background noise” of operating a service on the internet. The best way to stop someone breaking in is to not let them get to the front door in the first place, so let's try to stop that.</p><h2 id="option-0-if-you-like-it-put-a-hostname-on-it">Option 0: If you like it put a hostname on it</h2><p>The ALB rules allow you to specify a hostname, so you could set that to your domain name, and blackhole anything which doesn’t match. This covers about 80% of cases, as all they have is the IP and a port, but doesn’t stop someone with some basic knowledge of your infrastructure from bypassing the WAF. This is really a good idea regardless.</p><pre><code class="language-hcl">locals {
  environment = "test"
  
  domains = [
    "foo.com",
    "bar.com,
  ]
  
  route_priority = 10
  vpc_id         = "vpc-123456"
}

resource "aws_lb" "alb" {
  name = "${local.environment}-alb"

  ...
  
  load_balancer_type = "application"
  
  ...
}

resource "aws_lb_listener" "https_listener" {
  load_balancer_arn = aws_lb.alb.arn
  port              = "443"
  protocol          = "HTTPS"
  ssl_policy        = "ELBSecurityPolicy-2015-05"

  certificate_arn = var.certificate_arn

  # return a 403 by default
  default_action {
    type = "fixed-response"

    fixed_response {
      content_type = "text/plain"
      status_code  = "403"
    }
  }
}

resource "aws_lb_target_group" "target_group" {
  name     = "${local.environment}-service-name-tg"
  protocol = "HTTPS"
  port     = 4430

  health_check {
    ...
  }

  vpc_id = local.vpc_id
}

resource "aws_lb_listener_rule" "application_rule" {
  count        = length(local.domains)
  listener_arn = aws_lb_listener.https_listener.arn
  priority     = local.route_priority + count.index

  action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.target_group.arn
  }

  #you can only have one host header per rule, so make multiple rules?
  condition {
    field  = "host-header"
    values = [element(local.domains, count.index)]
  }
}</code></pre><h2 id="option-1-cloudfront-ip-list">Option 1: CloudFront IP list</h2><p>The official <a href="https://aws.amazon.com/blogs/security/how-to-automatically-update-your-security-groups-for-amazon-cloudfront-and-aws-waf-by-using-aws-lambda/">AWS way to do this is, of course, with a Lambda</a>.</p><p>AWS publish a list of CIDR ranges for their services - EC2, CloudFront and others - and they send an SNS message when this list is updated. You can trigger a lambda from that SNS message, and update the Security Group on the ALB to only allow traffic from those ranges.</p><p>This works, however it has a couple of problems.</p><ul><li>If the SNS message is dropped, you may have new or changed IP ranges which are sending you traffic, but you’re not allowing traffic from. AWS add new CloudFront POP’s on a regular basis, so this list is changing fairly often.</li><li>The list is fairly long, and a security group can only have 50 entries, so you have to manage splitting it over a number of security groups.</li></ul><p>AWS have handled the second one in <a href="https://github.com/aws-samples/aws-cloudfront-samples">their sample lambda</a>, but this has a number of moving parts which would be difficult to diagnose in the event of a problem.</p><p>I’d also recommend you add your own IP’s to this list, in case you need to bypass CloudFront for some reason, or put them in another security group.</p><h2 id="option-2-injected-header-and-waf">Option 2: Injected header and WAF</h2><p>CloudFront also has the option to inject a header with a fixed value before calling the origin. This header can be anything - prefixing it with <code>x-</code> is recommended - and the value can be anything. This makes it easy, for example, to inject a header with</p><pre><code>x-my-token: a1b2c3d4
</code></pre><p>You can then pick that up on the ALB side with a valid WAF which blocks all traffic, allowing only traffic with that header.</p><p>You do need to plan to keep the header field in sync, but as it’s not a real secret, you can put it into Terraform, or manually switch them out to rotate it.</p><p>Note that the value may end up in your logs, if you are logging headers. This can be more a volume/size issue than anything - I’ve had to avoid calling it <code>x-cloudfront-token: 7c9c2d3a-8033-4295-9b28-af8b0683353c</code> , which makes sense as it’s readable and a UUID is fairly unique, but it also adds 60-odd bytes (or 120 if everything is UTF-16 encoded) per request. It’s not massive, but it’s redundant and unnecessary.</p><p>I’d strongly suggest you set this up by hand - add the header in CloudFront, verify that it’s being sent correctly, then connect the WAF, possibly in COUNT mode rather than BLOCK, until you’re confident that it’s working.</p><pre><code>locals {
  environment        = "test"
  origin_domain_name = "loadbalancer_origin.foo.com"
  
  cloudfront_header_name = "x-cloudfront-token"
  cloudfront_token       = "7c9c2d3a-8033-4295-9b28-af8b0683353c"
}

resource "aws_cloudfront_distribution" "cloudfront" {
  
  ...
  
  enabled = true
  
  ...
  
  origin {
    domain_name = local.origin_domain_name
    
    
    ...
    
    custom_header {
      name  = local.cloudfront_header_name
      value = local.cloudfront_token
    }
  }
  ...
}

resource "aws_alb" "alb" {
  ...
}

resource "aws_wafregional_web_acl" "alb_waf" {
  metric_name = "albwaf"
  name        = "${local.environment}-web-alb-waf"

  default_action {
    type = "BLOCK"
  }

  rule {
    priority = 100
    rule_id  = aws_wafregional_rule.header_match_rule.id

    action {
      type = "ALLOW"
    }
  }
}

# bind it to the ALB
resource "aws_wafregional_web_acl_association" "web_waf_binding" {
  resource_arn = aws_alb.web_alb.arn
  web_acl_id   = aws_wafregional_web_acl.web_alb_waf.id
}

resource "aws_wafregional_rule" "header_match_rule" {
  depends_on  = ["aws_wafregional_byte_match_set.header_match_set"]
  name        = "${local.environment}_web_alb_header_match_rule"
  metric_name = "albheadermatchrule"

  predicate {
    negated = false
    type    = "ByteMatch"
    data_id = aws_wafregional_byte_match_set.header_match_set.id
  }
}


resource "aws_wafregional_byte_match_set" "header_match_set" {
  name  = "${local.environment}-web-alb_header_match_set"

  byte_match_tuples {
    text_transformation   = "NONE"
    target_string         = local.cloudfront_token
    positional_constraint = "EXACTLY"

    field_to_match {
      type = "HEADER"
      data = local.cloudfront_header_name
    }
  }
}</code></pre><p>If you need to bypass this with CURL, you can use the header option to set the value</p><pre><code>curl -k -H 'x-cloudfront-token: 7c9c2d3a-8033-4295-9b28-af8b0683353c' https://origin.server.com/foo/bar
</code></pre><p>This is the option we went with, and it's been working rather well. Disabling it if needed is a matter of just disconnecting the WAF-ALB association.</p><h2 id="option-3-injected-header-and-alb-rules">Option 3: Injected header and ALB rules</h2><p>The last option combines a few of the above options. It’s a little less flexible, if you are using ALB routing rules for other things, but it’s a lot cheaper (WAF costs per request, tho not a lot) and it has one fewer moving part - no WAF involved.</p><p>This involves setting the same header in CloudFront as in Option 2, but checking it in the Target Group routing rule, so you are matching on both the host name and the presence of the header value.</p><p>You need to have a fall thru for this - we’d normally just return 403 or 444 if nothing matches - but it’s fairly simple to implement and reason about.</p><p>You would setup CloudFront in the same way as <strong>Option 2</strong>. The ALB no longer needs a WAF, you'd just add more conditions to your listener rule</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://fastchicken.co.nz/content/images/2019/11/cloudfront-alb.png" class="kg-image" alt="Shut the back door - Locking an AWS ALB to CloudFront"></figure><p>At present, Terraform doesn't support this - they only have <code>host-header</code> and <code>path-pattern</code> - but <a href="https://github.com/terraform-providers/terraform-provider-aws/issues/8126">I'd assume that it's coming</a> (or I need to write some Go code)</p><hr><p>There are a couple of ways you can stop people bypassing your CloudFront protections, all of which are easy to implement and reason about, and very robust in production. </p><p>They will keep your back-end more secure, and make sure that all visitors to your sites pass thru the correct checks and filters.</p>]]></content:encoded></item><item><title><![CDATA[Using AWS WAF for IP restricting a CloudFront distribution]]></title><description><![CDATA[<p><a href="https://aws.amazon.com/cloudfront/">AWS CloudFront</a> is an extremely powerful service, which gives you a global Content Delivery Network (CDN) with over 100 points of presence, as well as robust DDOS protection and mitigation, edge caching, TLS termination, HTTP to HTTPS redirection, content streaming, and routing rules. Even with caching turned off, this is</p>]]></description><link>https://fastchicken.co.nz/2019/11/18/using-aws-waf-for-ip-restricting-a-cloudfront-distribution/</link><guid isPermaLink="false">5dd2e3c3857fc30001873ac9</guid><dc:creator><![CDATA[Nic Wise]]></dc:creator><pubDate>Mon, 18 Nov 2019 19:08:53 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1472222762265-7aa06b6f5826?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1472222762265-7aa06b6f5826?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=2000&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Using AWS WAF for IP restricting a CloudFront distribution"><p><a href="https://aws.amazon.com/cloudfront/">AWS CloudFront</a> is an extremely powerful service, which gives you a global Content Delivery Network (CDN) with over 100 points of presence, as well as robust DDOS protection and mitigation, edge caching, TLS termination, HTTP to HTTPS redirection, content streaming, and routing rules. Even with caching turned off, this is a service that you <strong>want</strong> to be fronting your website.</p><p>While it has a few flaws, like the time it takes to roll out a change, overall it's a solid, reliable and essential part of hosting a modern website. It can also be extended with <a href="https://aws.amazon.com/lambda/edge/">Lambda@Edge</a>, which allows you to run a lambda function on every request, which can modify parts of the result before sending it to the user.</p><p>One thing that CloudFront is missing, that a lot of people need, is <strong>IP whitelisting</strong>. This is useful if you want to lock your site down to a specific set of IP addresses - eg before a site launches - or in reverse, and more commonly, block a range of IPs from accessing your site.</p><p>Normally you could use a security group to handle the whitelisting - don’t allow from <code>0.0.0.0/0</code>, just put in the list of CIDRs you want to allow and you’re done. CloudFront, however, doesn’t support security groups, so this option isn’t available.</p><p>Enter the <a href="https://aws.amazon.com/waf/"><strong>AWS Web Application Firewall - WAF</strong></a>.</p><p>A WAF is normally used to inspect traffic for attacks like SQL Injection or Cross Site Scripting (XSS), and block them. Like <a href="https://en.wikipedia.org/wiki/Marmite">Marmite</a>, WAFs are universally loved (by PCI) or hated (by pretty much every developer and administrator who's had one forced on them). They are, however, very useful when done well.</p><p>As well as SQLi and XSS, the AWS WAF also has</p><ul><li>IP matching - a rule which matches if the source address is on a list of addresses</li><li>String and byte matching in various fields, using lists, partial matches and regular expressions</li><li>Custom WAF rules from 3rd party providers like Fortinet or AlertLogic</li><li><a href="https://aws.amazon.com/shield/">AWS Shield</a>, which provides DDOS mitigation (not proactive - that’s Shield Advanced, which is rather pricey, unless you need it, then it’s exceptionally cheap)</li></ul><p>The WAF consists of a number of pieces</p><ul><li>The <strong><a href="https://docs.aws.amazon.com/waf/latest/developerguide/web-acl-working-with.html">WAF ACL</a></strong> (Access Control List): a data structure which defines which rules your WAF contains, how it reports metrics and other configuration information. This is the root of the WAF structure and the entity that you attach to things which want to use the WAF.</li><li>A WAF ACL has one or more <strong><a href="https://docs.aws.amazon.com/waf/latest/developerguide/web-acl-rules.html">WAF Rules</a></strong> attached to it. If a rule matches, its <strong>action</strong> is applied (block, allow, count) and processing stops. Multiple rules in an ACL are applied in an <strong>OR</strong> manner. If no rules match, the default action applies.</li><li>A rule is made up of a list of <strong><a href="https://docs.aws.amazon.com/waf/latest/developerguide/web-acl-create-condition.html">predicates</a></strong> which are applied in an <strong>AND</strong> manner - for the rule to fire, you have to have (eg) an ip in the IP list predicate and also a specific string in a header field (string match predicate). <br><br>Predicates can also be negated (match if it’s <em>not</em> on the list). Each predicate has a matching type -  Byte, Geographic, IP, Regex, Size constraint, SQL Injection and Cross Site Scripting. </li><li>Each WAF Rule has one or more <strong>WAF Sets</strong> attached, eg a <em>IPSet</em>, <em>StringSet</em>, <em>GeoMatchSet</em>. This is a list of items which make up the predicate, and could be a list of IP addresses, a set of strings and fields to match, where to look for XSS and SQLi, areas of the world for a geographic match, or other configuration.</li><li>AWS WAF also supports <a href="https://aws.amazon.com/marketplace/solutions/security/waf-managed-rules">Managed Rules</a>, which can be bought in the AWS Marketplace. These do not have sets, and you can just include them, rather than providing any configuration.</li></ul><p>So a WAF ACL looks something like:</p><ul><li>If the IP is in the list, ALLOW (Rule, priority 1)</li><li>If the string is not in the list, BLOCK (Rule, priority 2)</li><li>If nothing above matched, COUNT (default action)</li></ul><p>If the user is blocked, they will receive a 403 error from CloudFront, which you can customize. This is different to a security group rule on an ALB, which will just ignore traffic that doesn't match.</p><h3 id="using-cloudfront-and-waf-to-pinhole-a-service">Using CloudFront and WAF to pinhole a service</h3><p>You can use CloudFront and WAF to easily pinhole a service to your IP address. You need to setup the following in Terraform</p><pre><code class="language-hcl">locals {
  # the name of the ACL, can have _ etc in it
  acl_id = "foo"

  # the name of the CloudWatch metric - must be a-z only
  metric_name = "foo"
  
  # the list of IPs we want to whitelist
  cidr_whitelist = [
  	"202.14.100.0/24",
    "8.8.8.8/32",
    "1.1.1.1/32",
  ]
}

resource "aws_waf_web_acl" "waf_acl" {
  name        = "${local.acl_id}_waf_acl"
  metric_name = "${local.metric_name}wafacl"

  default_action {
    type = "BLOCK"
  }

  rules {
    priority = 10
    rule_id  = aws_waf_rule.ip_whitelist.id

    action {
      type = "ALLOW"
    }
  }

  depends_on = [
    "aws_waf_rule.ip_whitelist",
    "aws_waf_ipset.ip_whitelist"
  ]
}

resource "aws_waf_rule" "ip_whitelist" {

  name        = "${local. acl_id}_ip_whitelist_rule"
  metric_name = "${local.metric_name}ipwhitelist"
  
  depends_on = ["aws_waf_ipset.ip_whitelist"]
  
  predicates {
    data_id = aws_waf_ipset.ip_whitelist.id
    negated = false
    type    = "IPMatch"
  }

}

resource "aws_waf_ipset" "ip_whitelist" {
  name = "${local. acl_id}_match_ip_whitelist"
  
  # dynamic below generates this from the list
  #
  # ip_set_descriptors {
  #   type = "IPV4"
  #   value = "8.8.8.8/32"
  # }

  dynamic "ip_set_descriptors" {
    for_each = toset(local.cidr_whitelist)

    content {
      type  = "IPV4"
      value = ip_set_descriptors.key
    }
  }
}
</code></pre><p>Once you have that, you can then connect it to the CloudFront distribution</p><pre><code class="language-hcl">resource "aws_cloudfront_distribution" "cloudfront" {
  ...
  web_acl_id = aws_waf_web_acl.waf_acl.id
  ...
}</code></pre><p>If you have more than one CloudFront distribution you want to use for this, you can attach the same ACL to multiple distributions, which does drop the cost a bit ($1/month). However, the management can be easier if it's one ACL per distribution, depending on how you structure your Terraform code.</p><p>You can also do this to an ALB or API Gateway, but you need to use the <code>aws_regional_waf_acl</code> structure (and other <code>regional</code> resources). The concept is identical.</p><p>While the black box nature of the SQLi and XSS rules can be frustrating at times, the other features of the AWS WAF are very useful, and can help you secure your site from unwanted attention.</p>]]></content:encoded></item><item><title><![CDATA[Cross-Account CodePipeline Deployments]]></title><description><![CDATA[<p>It’s becoming more common to split build and deployment infrastructure into distinct entities, and the account boundary in AWS is a good line to split things.</p><p>Some of the tools don’t handle this that well, tho. CodePipeline is definitely one of them.</p><p><a href="https://docs.aws.amazon.com/codepipeline/latest/userguide/pipelines-create-cross-account.html">AWS have documentation on how to</a></p>]]></description><link>https://fastchicken.co.nz/2019/07/01/cross-account-codepipeline-deployments/</link><guid isPermaLink="false">5d1a6449ba138e0001727c2f</guid><dc:creator><![CDATA[Nic Wise]]></dc:creator><pubDate>Mon, 01 Jul 2019 20:27:06 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1543674892-7d64d45df18b?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1543674892-7d64d45df18b?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Cross-Account CodePipeline Deployments"><p>It’s becoming more common to split build and deployment infrastructure into distinct entities, and the account boundary in AWS is a good line to split things.</p><p>Some of the tools don’t handle this that well, tho. CodePipeline is definitely one of them.</p><p><a href="https://docs.aws.amazon.com/codepipeline/latest/userguide/pipelines-create-cross-account.html">AWS have documentation on how to setup CodePipeline using remote resources</a>, but I found the document to have too many coded steps (which makes it specific to their situation) and lacking in general concepts. I’m going to try to address the latter.</p><figure class="kg-card kg-image-card"><img src="https://fastchicken.co.nz/content/images/2019/07/codepipeline.png" class="kg-image" alt="Cross-Account CodePipeline Deployments"></figure><h2 id="basic-structure">Basic structure</h2><p>This assumes you are building and deploying the following way:</p><ul><li>You have 2 accounts (could apply to more, but at minimum 2). One is for build / test and the other is for deployment / execution. I’m calling these <strong>build</strong> and <strong>test</strong> in here.</li><li>You are storing code in Git somewhere - <strong>Github</strong> in this case; building it in <strong>CodeBuild;</strong> and deploying it (in <strong>test</strong>) to a basic <strong>ECS Cluster</strong> and service. No Blue / Green, just redeploy the service with the new container and let ECS handle the deployment.</li><li><strong>CodePipeline</strong> is orchestrating things for you</li></ul><h2 id="environment-setup">Environment Setup</h2><p>CodePipeline needs a few things to get going, and as far as I can tell, they are difficult to do in the console, so I ended up using Terraform for it. I’m sure you could do them in the console and CLI, as the document above shows, I just found it easier to do it in Terraform. Plus, infrastructure as code. It's a good thing.</p><p>First, it needs somewhere to store the artefacts. This is a normal <strong>S3 bucket</strong> in the <strong>build</strong> account. The <strong>test</strong> account will need access to this, so you need to make sure that the bucket policy includes the <code>root</code> user in <strong>test</strong> having access to the bucket.</p><pre><code class="language-json">{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::TEST_ACCOUNT_ID:root"
                ]
            },
            "Action": [
                "s3:PutObject",
                "s3:GetObjectVersion",
                "s3:GetObject",
                "s3:GetBucketLocation",
                "s3:GetBucketAcl"
            ],
            "Resource": [
                "arn:aws:s3:::BUCKET_NAME/*",
                "arn:aws:s3:::BUCKET_NAME"
            ]
        },</code></pre><p>Next, you will need to make a custom KMS key and alias. Again, the <code>root</code> user of <strong>test</strong> needs access to this as a user, as does the role that CodeBuild and CodePipeline and running as. It doesn’t matter who can administrate it.</p><pre><code class="language-json">{
    "Sid": "",
    "Effect": "Allow",
    "Principal": {
        "AWS": [
            "arn:aws:iam::TEST_ACCOUNT_ID:root",
            "arn:aws:iam::BUILD_ACCOUNT_ID:role/CODE_PIPELINE_ROLE",
            "arn:aws:iam::BUILD_ACCOUNT_ID:role/CODE_BUILD_ROLE"
        ]
    },
    "Action": [
        "kms:ReEncrypt*",
        "kms:GenerateDataKey*",
        "kms:Encrypt",
        "kms:DescribeKey",
        "kms:Decrypt"
    ],
    "Resource": "*"
},
{
    "Sid": "",
    "Effect": "Allow",
    "Principal": {
        "AWS": [
            "arn:aws:iam::TEST_ACCOUNT_ID:root",
            "arn:aws:iam::BUILD_ACCOUNT_ID:role/CODE_PIPELINE_ROLE",
            "arn:aws:iam::BUILD_ACCOUNT_ID:role/CODE_BUILD_ROLE"
        ]
    },
    "Action": [
        "kms:RevokeGrant",
        "kms:ListGrants",
        "kms:CreateGrant"
    ],
    "Resource": "*",
    "Condition": {
        "Bool": {
            "kms:GrantIsForAWSResource": "true"
        }
    }
}</code></pre><p>You can also set it as the default key to use for encryption in the S3 bucket, tho that’s optional. CodePipeline and CodeBuild will upload with an encryption key regardless of the bucket setup.</p><p>Finally, you’ll need an ECR repository to store the container, and that will need to allow the <strong>test</strong> account <code>root</code> user to pull from it.</p><h2 id="build-setup">Build Setup</h2><p>You will need a CodeBuild project which will do the container build, and push it to ECR.</p><p>This has <code>CODEPIPELINE</code> as the input and output artefact types, and it also must include a reference to the KMS key you created, otherwise CodeBuild will use the default <code>aws/s3</code> key when it uploads artefacts, otherwise the <code>test-deployment</code> role in <strong>test</strong> will not be able to get to the artefacts. You can't share the default key between accounts.</p><p>Your build project also needs to output a file called <code>imagedefinitions.json</code>. The end of it is likely to look like this</p><pre><code class="language-yml">version: 0.2
phases:
  ...
  post_build:
    commands:
      - echo Build completed on `date`
      - echo Pushing the Docker image...
      - docker push $IMAGE_REPO_NAME:$IMAGE_TAG
      - echo finished
      - printf '[{"name":"%s","imageUri":"%s"}]' "app" "$IMAGE_REPO_NAME:$IMAGE_TAG" | tee imagedefinitions.json
artifacts:
  files: imagedefinitions.json

</code></pre><p>This contains the name of the container in the Task Definition (<code>app</code> in this case) and the URL of the new image in ECR (eg <code>123456789012.dkr.ecr.us-west-2.amazonaws.com/my_thing:latest</code>)</p><h2 id="remote-account-setup">Remote Account Setup</h2><p>In the remote account, you will need a role (<code>test-deployment</code>) which can be assumed from the <strong>build</strong> account, and can manipulate ECS, EC2, and load balancing. It’ll also need access to the S3 bucket and the KMS key (mostly for decryption).</p><h2 id="pipeline-setup">Pipeline setup</h2><p>You can now setup your <strong>CodePipeline</strong>. You will need to use the bucket you made above, and be sure to set the encryption key for use there.</p><p>The rest of the pipeline is pretty much as-is, except the deploy step - this also needs the role setting, to be the <code>test-deployment</code> role you made in <em>Remote Account Setup</em>. Your CodePipeline role will need to be able to assume that role.</p><pre><code class="language-json">// Trust relationship in test-deployment
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::BUILD_ACCOUNT_ID:root"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

// assume role section in the codepipeline role
{
    "Sid": "",
    "Effect": "Allow",
    "Action": "sts:AssumeRole",
    "Resource": [
        "arn:aws:iam::TEST_ACCOUNT_ID:role/*"
    ]
},
{
    "Sid": "",
    "Effect": "Allow",
    "Action": "iam:PassRole",
    "Resource": "*"
}</code></pre><p>You may want to further limit which roles the CodePipeline role can assume (not <code>role/*</code>) and which roles can be passed.</p><h2 id="execution">Execution</h2><p>The pipeline executes like this:</p><ul><li><strong>CodePipeline</strong> is watching the <strong>Git</strong> repo (or gets a Webhook), gets the source down, zips it and puts it into S3, encrypted with the KMS key.</li><li><strong>CodeBuild</strong> is started, and pointed at the artefacts. CodeBuild gets the artefacts from S3, runs the build, and puts the output artefacts into S3, again using the KMS key.</li><li><strong>CodePipeline</strong> assumes the provided role into the <strong>test</strong> account, and makes a new Task Definition with the <code>imageUri</code> from <code>imagedefinitions.json</code>, and then deploys that into ECS.</li><li><strong>ECS</strong> handles the load balancer, adding the new containers in and removing the old ones once the new ones are healthy.</li></ul><h2 id="things-that-tripped-me-up">Things that tripped me up</h2><ul><li><strong>The KMS key in CodeBuild.</strong> I had assumed that CodePipeline, which had been told about the key, received the artefacts and put them into S3, but it’s CodeBuild which does that, so it needs to be aware of which KMS key to use. It defaults to <code>aws/s3</code> which can't be used outside of the current account.</li><li>The role which is being assumed in <strong>test</strong> needs to not just deploy a service, but also manipulate the other services that you need to get a container out - elastic load balancing, EC2, and anything else you need.</li></ul><p>Once setup, this works nicely and could be easily extended to have further steps to wait for intervention, then promote to <strong>prod</strong> after it’s been on <strong>test</strong> and is accepted. </p><p>I don’t believe you can do much of this in the console - you have to use something like terraform (fairly easy) or the CLI (harder, but not impossible). CodePipeline has been described to me as a set of Lego - all the bits are there, you just have to do a LOAD of work to wire it up, especially if you want to do things which are outside of the flows that the setup wizard does. Even editing the pipeline after it's created hides a lot of the configuration - I think AWS could do a lot of work here, even if it’s just exposing the json behind the pipeline, as they do with IAM (json vs the visual editor).</p>]]></content:encoded></item><item><title><![CDATA[Posting from the iPad - using Bear (well, maybe)]]></title><description><![CDATA[<p>I've been using <a href="https://bear.app/">Bear</a> for writing and note taking for a while. It's a Markdown editor, but it also syncs nicely (iCloud) between my Macs, iPhone and iPad. <a href="https://fastchicken.co.nz/2019/04/26/blogging-on-the-ipad/">It works great for writing blog posts, too.</a></p><p><a href="https://blog.bear.app/2019/05/introducing-a-new-way-to-publish-bear-notes-to-wordpress-on-ipad-and-iphone/">From the Bear blog</a></p><blockquote>This got us thinking: what if we could make it</blockquote>]]></description><link>https://fastchicken.co.nz/2019/05/13/posting-from-the-ipad-using-bear-well-maybe/</link><guid isPermaLink="false">5cd9cb0d1b50430001a44ae4</guid><dc:creator><![CDATA[Nic Wise]]></dc:creator><pubDate>Mon, 13 May 2019 20:00:21 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1528297506728-9533d2ac3fa4?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1528297506728-9533d2ac3fa4?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=2000&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Posting from the iPad - using Bear (well, maybe)"><p>I've been using <a href="https://bear.app/">Bear</a> for writing and note taking for a while. It's a Markdown editor, but it also syncs nicely (iCloud) between my Macs, iPhone and iPad. <a href="https://fastchicken.co.nz/2019/04/26/blogging-on-the-ipad/">It works great for writing blog posts, too.</a></p><p><a href="https://blog.bear.app/2019/05/introducing-a-new-way-to-publish-bear-notes-to-wordpress-on-ipad-and-iphone/">From the Bear blog</a></p><blockquote>This got us thinking: what if we could make it a little easier for Bear users to publish their writing? Once again, our Marketing &amp; Research Division sprung into action to find where all the hip kids publish essays online.<br><br>With today’s update to <a href="https://itunes.apple.com/us/app/wordpress/id335703880">WordPress for iOS</a>, you can now publish Bear notes to WordPress blogs. It’s really simple to use:<br>First, make sure you update <a href="https://itunes.apple.com/us/app/bear/id1016366447">Bear</a> and <a href="https://itunes.apple.com/us/app/wordpress/id335703880">WordPress</a><br>In Bear, tap the share sheet at the top right of a note<br>Tap WordPress in the top row of options (learn <a href="https://support.apple.com/guide/iphone/install-app-extensions-iph1750a2241/ios">how to enable app extensions on iOS</a>)<br>The WordPress app will open. If you have multiple blogs, a screen will appear so you can pick one as your post’s destination<br>A draft screen will appear with your post filled in, complete with proper formatting of all headings, links, text styles, lists, and even photos</blockquote><figure class="kg-card kg-image-card"><img src="https://fastchicken.co.nz/content/images/2019/05/Bear-to-WordPress-example.gif" class="kg-image" alt="Posting from the iPad - using Bear (well, maybe)"></figure><p>In theory, I should be able to write a small app which just logs into Ghost, pulls down the posts, allows them to be exported as <a href="https://github.com/shinyfrog/TextBundle">TextBundle</a> files (into Bear) or allows them to be shared to as <a href="https://github.com/shinyfrog/TextBundle">TextBundles</a>. They even have source code for it.</p><p>This would make it SO much easier, I think. Much better than trying to recreate the full editing environment, and keep it up to date with Ghost.</p><p>Side project, found.</p>]]></content:encoded></item><item><title><![CDATA[West Coast Wandering. (2019)]]></title><description><![CDATA[<p><strong>Getting there</strong></p><p>As is often the case, getting there is half the fun. Or half the un-fun in this case.</p><p>Before we even left - about 4 weeks before - <a href="https://www.radionz.co.nz/news/national/387006/waiho-bridge-reopens-after-being-rebuilt-in-18-days">a huge storm went thru the west coast</a>, dumping between 600 and 1000mm of rain in 24 hours. This took</p>]]></description><link>https://fastchicken.co.nz/2019/04/26/west-coast-wandering-2019/</link><guid isPermaLink="false">5cc177b5c7517a00014bd911</guid><dc:creator><![CDATA[Nic Wise]]></dc:creator><pubDate>Fri, 26 Apr 2019 06:19:23 GMT</pubDate><media:content url="https://fastchicken.co.nz/content/images/2019/04/E1C71BB1-C67B-40F9-A2F9-EEF8E7E00F71.jpeg" medium="image"/><content:encoded><![CDATA[<img src="https://fastchicken.co.nz/content/images/2019/04/E1C71BB1-C67B-40F9-A2F9-EEF8E7E00F71.jpeg" alt="West Coast Wandering. (2019)"><p><strong>Getting there</strong></p><p>As is often the case, getting there is half the fun. Or half the un-fun in this case.</p><p>Before we even left - about 4 weeks before - <a href="https://www.radionz.co.nz/news/national/387006/waiho-bridge-reopens-after-being-rebuilt-in-18-days">a huge storm went thru the west coast</a>, dumping between 600 and 1000mm of rain in 24 hours. This took out one of the bridges on the main road - the only road - just outside of Franz Joseph. We managed to book around this, but that would have cut off about 30% of the trip, and added about 6 hours more driving to an already driving-heavy trip. </p><p>Thankfully, the army and other engineers rebuilt a bailey bridge in about 2 weeks, so the week before we were meant to leave, it was all back up and running, so we were back to our original plans and bookings.</p><p>We’d opted to rebook our flights to get down 5 hours earlier, as our original plans involved staying in Christchurch the first night. However, on the day, AirNZ was having none of this, and while we got to the airport for our 10am flight, we didn’t manage to leave until 1pm. Still, 2 extra hours was great, as we got thru Arthurs Pass in daylight, and to our first nights accomodation just after dark.</p><p>Once we were in Christchurch, we remembered that it was Good Friday, so all but essential shops were shut. With no groceries for the first day, we were able to get some takeaways and gas and get on our way, feeling only a bit sheepish.</p><p>Not off to a good start, but it could have been a lot worse. We could have been “not on holiday”.</p><p><strong>Unwinding at the Woodpecker Hut</strong></p><p>Now, to say that the two of us needed a break is an understatement. Burnt out and exhausted would be closer to the truth. Our first stop was the <a href="https://www.canopycamping.co.nz/woodpecker-hut">Woodpecker Hut near Punakaiki</a>. We’d intentionally left the first full day empty of things to do, so after waking up (and totally forgetting to bring coffee), we headed into Greymouth, which is about a 40min drive south, to get supplies.</p><p>Stocked up on wine, coffee, chocolate and chips, we headed back to fire up the outdoor, wood-fired hot tub and relax with the local Te Chickens (Weka)</p><figure class="kg-card kg-image-card kg-width-full kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/04/6E3A8BB9-8190-4669-A61A-A709714754C6.jpeg" class="kg-image" alt="West Coast Wandering. (2019)"><figcaption>Weka. AKA Te Chicken. They have a reputation for stealing things, but this one was on his best behaviour.</figcaption></figure><p>On the second day, after a quick morning soak in the tub, we headed north to Westport, via Cape Foulwind, inland to Inagahua, with a stop at the old ghost town at Waiuta, then up to Arthurs Pass for a proper look around.</p><p>Arthurs Pass really turned on the weather - or rather, turned on the rain. By the time we got up there, it was chucking it down and misty, which set the tone quite nicely. The Kea, however, didn’t mind, and we had a nice, if fairly short and wet, walk up to the Devils Punchbowl in the rain.</p><figure class="kg-card kg-image-card kg-width-full kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/04/4CF2115B-FFB9-4CDC-9DB1-596B06C3AC6B.jpeg" class="kg-image" alt="West Coast Wandering. (2019)"><figcaption>Devils Punchbowl, and a soggy, but warm, photographer.</figcaption></figure><p>Sadly, our time at Woodpecker Hut was done, and we fired up the hot tub one last time and enjoyed the roar of the southern ocean.</p><figure class="kg-card kg-image-card kg-width-full kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/04/1B19773D-8BAD-40E9-8D32-6126FA967E45.jpeg" class="kg-image" alt="West Coast Wandering. (2019)"><figcaption>Woodpecker Hut</figcaption></figure><figure class="kg-card kg-image-card kg-width-full kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/04/28CFC739-73B6-43BC-BB23-774A7D29C966.jpeg" class="kg-image" alt="West Coast Wandering. (2019)"><figcaption>The West Coast. Sort of like Big Sur, but better and with a lot less people.</figcaption></figure><p></p><p><strong>Okarito</strong></p><p>Our next stop was a couple of hours south in Okarito, which is an old port town and large wetland, and home to, amongst other things, <a href="https://en.m.wikipedia.org/wiki/Okarito_kiwi">Rowi Kiwi</a>, which are a rare subspecies of Kiwi. There are only about 600 of them left, and they only exist within the Okarito area. It’s also home to Kotuku (Great White Heron), and a lot of others.</p><p>We arrived in Okarito right on sunset, and it was spectacular.</p><figure class="kg-card kg-image-card kg-width-full"><img src="https://fastchicken.co.nz/content/images/2019/04/D6E74181-4EFB-49DE-BA30-1E1281F1B959.jpeg" class="kg-image" alt="West Coast Wandering. (2019)"></figure><p>The next day, we headed south to Lake Matheson, and down as far as Bruce Bay, which had a great ice cream shack right on the beach.</p><figure class="kg-card kg-image-card kg-width-full kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/04/9BC55CA0-DF99-4218-8336-D9364CA27CF8.jpeg" class="kg-image" alt="West Coast Wandering. (2019)"><figcaption>Lake Matheson. Pays to wait a bit for the water to become still.</figcaption></figure><p>On the last day, we headed out on a boat trip into the Okarito Lagoon. It’s normally a bird watching trip (I think we dropped the average age down by about 20 years), but it wasn’t the right time of year for most of the birds. Still, we saw a few Kotuku, some of the other wetland dwellers, and when we were parked up having morning tea, a group of 4 <a href="https://en.m.wikipedia.org/wiki/Kea">Kea</a> landed in the trees above us and proceeded to eat the berries, calling and laughing to each other. Magic.</p><p>From there we headed south again....</p><p><strong>Haast and Makarora</strong></p><p>Next proper stop was Haast, and lunch at Hard Antler in Haast, which is as hard case and kiwi as you might expect. We drove out to Jackson Bay, which is as far south as you can go on the west coast without a proper four-wheel drive. It very much feels like the end of the road there, with a couple of houses and an outpost of the local crayfish company. We did find a pod of <a href="https://www.doc.govt.nz/nature/native-animals/marine-mammals/dolphins/hectors-dolphin/">dolphins</a> (hectors we think, but not sure) swimming and hunting around the rocks on the way out, and Leonie got a couple of good photos of them playing.</p><figure class="kg-card kg-image-card kg-width-full kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/04/83F2F350-ED10-4E96-BFF2-F732362A7DDF.jpeg" class="kg-image" alt="West Coast Wandering. (2019)"><figcaption>Airtime!</figcaption></figure><p>From Haast, we went over the Haast Pass to Makarora. The Haast Pass is quite low compared to Arthurs - you don’t need to climb much to get over it. There are some spectacular views up there tho, and the river it follows is a beautiful light blue.</p><p><strong>Tekapo</strong></p><p>Makarora is a fair way up the river valley at the top of Wanaka, so it was quite cold when we woke up. We headed off to the Blue Pools, which would be lovely for a swim on a warmer day, then down to Wanaka for an amazing Burrito from <a href="http://www.burritocraft.co.nz">Burrito Craft</a> and some gas, and headed over the Lindis Pass to Tekapo.</p><figure class="kg-card kg-image-card kg-width-full kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/04/A7D8DC1F-6E41-48B1-9E80-041CAB02655D.jpeg" class="kg-image" alt="West Coast Wandering. (2019)"><figcaption>Lindis Pass</figcaption></figure><p>This area reminds me a lot of the Scottish Highlands, except the hills are a bit taller, to the agreement of a travelling Scot I was talking to on the top of the pass. Like the Highlands, it’s stunning country to drive thru.</p><p>We ended the day at Tekapo, which is a <a href="https://en.m.wikipedia.org/wiki/Dark-sky_preserve#Dark-Sky_Preserves.2C_Reserves_and_Parks">Dark Sky Preserve</a>. </p><p>The following morning, we headed up to Mt Cook, which is about an hours drive from Tekapo. As we have had the whole trip, the weather has been perfect, usually clear blue skies, and today was no exception. Mt Cook was out and cloud-free, and the view from Now-lake-formally-glacier Tasman, down the valley, was stunning.</p><figure class="kg-card kg-image-card kg-width-full kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/04/3F97AAC9-6CCC-4FCF-A785-71B373A8FCA7.jpeg" class="kg-image" alt="West Coast Wandering. (2019)"><figcaption>Mt Cook, out in the sun, from Kea Point. Which had a disappointing lack of Kea</figcaption></figure><figure class="kg-card kg-image-card kg-width-full kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/04/3F1BF0BE-5A80-4483-A47C-070D2CE22054.jpeg" class="kg-image" alt="West Coast Wandering. (2019)"><figcaption>Down the Valley from Lake Tasman</figcaption></figure><p>Lake Tasman is now a lake, with a glacier at it's head, about 5 or 6km long. In 1990, the whole area was a fully formed glacier. It's receeding at about 0.5-1km/year at the moment. The othor major glaciers - Fox, Franz Joseph - are receeding at a similar rate, and you can no longer drive or walk to them. </p><p>These will have gone from "normal" to gone in my lifetime.</p><p>Just let that sink in.</p><hr><p>Thats pretty much the end of our holiday. I'm writing this in Tekapo, and we fly back to Auckland tomorrow, and work on Monday. It's been a wonderful, and well-earned, break, and like all holidays, isn't nearly long enough. We could have spent the whole week up around Woodpecker Hut, or the whole week around Okarito or Haast. We'll just have to come back. </p><hr><p><strong>Observations</strong></p><p>If you think that cellphone cameras are not valid, primary-use cameras, you are just wrong. I saw a mix of large screen phones (maybe 95%), DSLRs (4%) and a few compact or micro 4/3's. Phone photography is what people are using. They are the current point and shoot.</p><p>The number of people doing things which have no purpose except Instagram or YouTube is disturbing and disappointing.</p><figure class="kg-card kg-image-card kg-width-full kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/04/CD1F0D9F-9D79-4391-9157-E7BC5415F8D7.jpeg" class="kg-image" alt="West Coast Wandering. (2019)"><figcaption>Lets huddle around and not look at the view and decide which image to put in the Instagram Story. FFS.</figcaption></figure><p>So many people getting to places which have amazing natural beauty, then seemingly ignoring it, after taking a couple of pictures, and just huddling around discussing which picture they should add to their Instagram Story. Then leaving. Or walking around looking at the back of a phone or gopro, rather than at the mountain they were filming. And then there were the drones (tho there are also a <em>lot</em> of no-drone signs, basically all of the national parks).</p><p>Lake Matheson was the most obvious example of this, but it was in a lot of the places we went.  (I could understand enough German to know roughly what they were saying)</p><p>Previously, I could never understand the Japanese, who’d flood out of a tour bus, take 100 photos (or video), then get back on the bus, until I talked to a Japanese friend who explained that they get around 2 weeks per year when they can take a holiday that they choose - what we'd call annual leave - and they have to cram in as much as they can. They live off the photos and video for months and years after. (They get more holidays, it's just public holidays where they don’t get to pick the days).</p><p>I’m not sure there is going to be as reasonable an explanation for the Instabook crowd.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/04/EAD3E78B-29BB-4D4F-B92E-431FF97066C8.jpeg" class="kg-image" alt="West Coast Wandering. (2019)"><figcaption>You know all those photos of that tree in the water at Wanaka - well, this is the "behind the scenes" shot. There were 10x the number of people that you can see, including someone with a lighting rig, shooting a woman in a wedding dress (not a bridal photo tho).</figcaption></figure><p>There’s a lot of people down the west coast, and it’s not summer anymore. We (NZ) need to spend a LOT more money on resources - toilets at camping areas and tourist spots, roads, track maintenance - otherwise <a href="https://www.radionz.co.nz/news/national/385913/fewer-freedom-camping-problems-in-south-island-this-summer-authorities">the flood of people is going to seriously damage the already heaving environment</a>. Even more so in places like Queenstown and Wanaka. If only the government could borrow at historically low rates...</p>]]></content:encoded></item><item><title><![CDATA[Blogging on the iPad]]></title><description><![CDATA[<p>The <a href="https://fastchicken.co.nz/2019/04/26/west-coast-wandering-2019/">previous blog post</a>, about the West Coast, was done end-to-end on my iPad with an external keyboard. This is something I’ve been trying to work out - how I can move more of my day to day stuff to the iPad, rather than refresh my ageing 2012 retina</p>]]></description><link>https://fastchicken.co.nz/2019/04/26/blogging-on-the-ipad/</link><guid isPermaLink="false">5cc2b308c7517a00014bda3c</guid><dc:creator><![CDATA[Nic Wise]]></dc:creator><pubDate>Fri, 26 Apr 2019 05:00:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1528988719300-046ff7faf8cb?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1528988719300-046ff7faf8cb?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=2000&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Blogging on the iPad"><p>The <a href="https://fastchicken.co.nz/2019/04/26/west-coast-wandering-2019/">previous blog post</a>, about the West Coast, was done end-to-end on my iPad with an external keyboard. This is something I’ve been trying to work out - how I can move more of my day to day stuff to the iPad, rather than refresh my ageing 2012 retina MacBook Pro.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/04/DAD15B6C-3DCD-4744-979E-6A9142759EA9.jpeg" class="kg-image" alt="Blogging on the iPad"><figcaption>Current setup of Bear, iPad, Apple Wireless Keyboard, Hipster-as-fuck block of wood as a stand, and glass of wine.</figcaption></figure><p>The main goal here is two-fold - to improve my writing and communication skills, and also to see how far I can go with an iPad, rather than with macOS.</p><p>At present, I use the iPad for about 95% of non-development stuff - reading, writing, general internet use - and it’s the device I take with me when I travel.</p><p>I use my personal laptop (or my work laptop) for the other 5%, and any development or infrastructure stuff I need to do.</p><p>While <a href="https://bear.app">Bear</a> is fantastic to write Markdown in, <a href="https://ghost.org">Ghost</a>, the software I use to publish this blog, doesn’t play nicely with the iOS browser. It works, mostly, but has some warnings and a few minor bugs.</p><p>Some people have tried to do an iOS app for Ghost - <a href="https://github.com/Cantallops/Phantom">Phantom</a> - but it’s stagnated for the past 12 months. I plan to have a look at that when I get back.</p><p>So this was an experiment to see if it would work, and so far, it did. I managed to write all the words, and take, pick and edit the photos, all on either my iPhone 8 or iPad. It’s not perfect, but it’s a good start. A better iPhone wouldn’t have changed much, tho a newer iPad (or a pro) might have.</p><p>Another option would be to move back to Wordpress, but I don’t think I want to do that. It’s “ok”, and I run a few Wordpress instances already for others, but I like the ethos of Ghost, even if this area is lacking a bit. There are other options like Jekyll or Github Pages, which could also work with some infrastructure.</p><hr><p>The next big bit I want to be able to do is infrastructure or development tasks - doing Terraform, changing lambdas etc. I have Pythonista for python stuff, and a Git client, but neither of them is very good for what I want, and I’m lacking a decent code editor. I can easily SSH into a remote EC2 instance to do the actual execution of whatever I’m doing, so I don’t need to run it on the iPad. I can just as easily VPN into home and SSH into my Ubuntu-running Mac Mini. Terminals are a nicely solved problem with the likes of Prompt or even iSH, which is a full Alpine install, inside an iOS sandbox.</p><p>I’m really hoping that <a href="https://aws.amazon.com/cloud9/">AWS Cloud9</a> might work, in Web View rather than in Safari. I’m yet to try that out, but it already does all the editing, syncing with the remote EC2 instance, and machine management.</p><p>Having that on the iPad in some sensible way would be amazing.</p>]]></content:encoded></item><item><title><![CDATA[See a pontoon. Swim to a pontoon. Jump from a pontoon]]></title><description><![CDATA[<p>A wise couple, <a href="https://www.thedolectures.com/talks/alice-and-ross-beese-on-the-road">Alice and Ross</a>, once told me:</p><blockquote>If there is a river, or even the sea, go jump in it</blockquote><p>We don't have rivers on Waiheke. But we do have lots of ocean  </p><figure class="kg-card kg-image-card"><img src="https://fastchicken.co.nz/content/images/2019/01/C864B8EC-9FBA-4BFF-98D7-04D035D6486A.jpeg" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="https://fastchicken.co.nz/content/images/2019/01/1547868286.jpg" class="kg-image"></figure>]]></description><link>https://fastchicken.co.nz/2019/01/19/see-a-pontoon-swim-to-a-pontoon-jump-from-a-pontoon/</link><guid isPermaLink="false">5c42d931e7bdcd044aa0f70f</guid><dc:creator><![CDATA[Nic Wise]]></dc:creator><pubDate>Sat, 19 Jan 2019 08:15:15 GMT</pubDate><media:content url="https://fastchicken.co.nz/content/images/2019/01/1547868286-1.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://fastchicken.co.nz/content/images/2019/01/1547868286-1.jpg" alt="See a pontoon. Swim to a pontoon. Jump from a pontoon"><p>A wise couple, <a href="https://www.thedolectures.com/talks/alice-and-ross-beese-on-the-road">Alice and Ross</a>, once told me:</p><blockquote>If there is a river, or even the sea, go jump in it</blockquote><p>We don't have rivers on Waiheke. But we do have lots of ocean  </p><figure class="kg-card kg-image-card"><img src="https://fastchicken.co.nz/content/images/2019/01/C864B8EC-9FBA-4BFF-98D7-04D035D6486A.jpeg" class="kg-image" alt="See a pontoon. Swim to a pontoon. Jump from a pontoon"></figure><figure class="kg-card kg-image-card"><img src="https://fastchicken.co.nz/content/images/2019/01/1547868286.jpg" class="kg-image" alt="See a pontoon. Swim to a pontoon. Jump from a pontoon"></figure>]]></content:encoded></item><item><title><![CDATA[Getting started with Github Actions]]></title><description><![CDATA[<p>A while back, Github announced <a href="https://github.com/features/actions/">Github Actions</a>, which is a containerised platform for running things when you do something in Github, like make a PR, comment, etc.</p><figure class="kg-card kg-image-card"><img src="https://fastchicken.co.nz/content/images/2019/01/44036562-2.png" class="kg-image"></figure><p>On the surface, it looks like a very nice wrapper over the top of their existing web-hook apis, with container execution infrastructure for</p>]]></description><link>https://fastchicken.co.nz/2019/01/14/getting-started-with-github-actions/</link><guid isPermaLink="false">5c3cdd5bf16c0b6932bc31cb</guid><dc:creator><![CDATA[Nic Wise]]></dc:creator><pubDate>Mon, 14 Jan 2019 23:23:41 GMT</pubDate><media:content url="https://fastchicken.co.nz/content/images/2019/01/Screen-Shot-2019-01-15-at-12.19.24.png" medium="image"/><content:encoded><![CDATA[<img src="https://fastchicken.co.nz/content/images/2019/01/Screen-Shot-2019-01-15-at-12.19.24.png" alt="Getting started with Github Actions"><p>A while back, Github announced <a href="https://github.com/features/actions/">Github Actions</a>, which is a containerised platform for running things when you do something in Github, like make a PR, comment, etc.</p><figure class="kg-card kg-image-card"><img src="https://fastchicken.co.nz/content/images/2019/01/44036562-2.png" class="kg-image" alt="Getting started with Github Actions"></figure><p>On the surface, it looks like a very nice wrapper over the top of their existing web-hook apis, with container execution infrastructure for free. Oh, and <a href="https://github.com/actions">a library of existing stuff you can use</a>.</p><p>I signed up for the beta, and eventually got in, only to find that it was private repos only - and I couldn't make them (I can now). Today, I came across <a href="https://twitter.com/jessfraz">@jessfraz</a> (<a href="https://twitter.com/jessfraz">Jessie Frazelle</a>) blog post on <a href="https://blog.jessfraz.com/post/the-life-of-a-github-action/">The Life of a Github Action</a>, which is a nice, small, understandable introduction to making a small Action. I decided to use my ferry ride to look into it again. But.... </p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet"><p lang="en" dir="ltr">I hit something every. damn. time. I find some space to try out actions.<br><br>Oh, it&#39;s beta (signed up)<br>Oh, it&#39;s private repos only (now fixed, thanks <a href="https://twitter.com/natfriedman?ref_src=twsrc%5Etfw">@natfriedman</a>)<br>Oh, I have <a href="https://twitter.com/jessfraz?ref_src=twsrc%5Etfw">@jessfraz</a> awesome blog post! Oh, the docs are down... :facepalm:<br><br>Pretty sure they will fix this one tho :)</p>&mdash; Nic Wise (@fastchicken) <a href="https://twitter.com/fastchicken/status/1084873475716612101?ref_src=twsrc%5Etfw">January 14, 2019</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</figure><p>Eventually, the docs came back up (Thanks Jess and Brendan)</p><p><strong>My goal for this is to scratch a small itch we have at work</strong>. We tag PRs with <code>ready for review</code> when they are ready, and a webhook look at that, and posts it off into Slack for us, someone sees it, reviews it, and then does the PR approval flow to approve it, and finally, marks it as <code>ready to land</code>.</p><figure class="kg-card kg-image-card"><img src="https://fastchicken.co.nz/content/images/2019/01/Screen-Shot-2019-01-15-at-12.12.43.png" class="kg-image" alt="Getting started with Github Actions"></figure><p>We used to just do the last bit, before approvals arrived. Now we have to do both. It's only one more click, but it's also difficult to do on mobile, and we have a few bits which trigger off that flag being set.</p><p>So, I started hacking on it. The actual function is quite simple, and I've included the code below (until I make the repo public), but here's some of the issues I hit, which might be in the docs.... which I couldn't read.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/01/Screen-Shot-2019-01-15-at-12.11.36.png" class="kg-image" alt="Getting started with Github Actions"><figcaption>The action. Not exactly complicated.</figcaption></figure><p><strong>First, you can have actions locally.</strong> I thought I had to refer to another public repository, or initially, a docker registry. But no, you can have it in the same repo, which is awesome.</p><pre><code>action "tag on approve" {
    uses = "./tag-on-review/" &lt;--- this is local to my project
    secrets = ["GITHUB_TOKEN"]
}</code></pre><pre><code>.github/
  main.workflow

tag-on-review/
  Dockerfile
  tag-on-review.sh

</code></pre><p>I was using a PR as a test, but committing to master for the workflow and container. It took a few goes to realise that the workflow which was being executed is the one inside the branch!</p><blockquote>So <strong>Protip:</strong> Use another repo for your workflow actions, not the local one. Then you can tie it to a specific branch with <code>uses = "nicwise/my-action@master"</code> and not have this problem. Downside is, the repo has to be public. I really hope I can have a mono-repo for these, I don't want a repo with just one shell script and a Dockerfile.</blockquote><p><strong>There is a bit in the workflow</strong> which talks about the <code>GITHUB_TOKEN</code>, which is marked as a secret. Actions provides secret management (awesome!) so I was expecting to have to set this - but this one appears to be a special case, and it's just injected in. Nice.</p><pre><code>action "tag on approve" {
    uses = "./tag-on-review/"
    secrets = ["GITHUB_TOKEN"] &lt;-- special unicorn. 
# If you make your own, you need to add them into the UI in Settings -&gt; Secrets
}</code></pre><p><strong>The content of the event</strong> is provided for you. You don't get a URL, it's just a local file - all very concourse-y, which is good. You can then just run <code>jq</code> over it to get stuff out, if you are using <code>bash</code>. Otherwise, pick your preferred Json parser.</p><pre><code>action=$(jq --raw-output .action "$GITHUB_EVENT_PATH")
pr_url=$(jq --raw-output .pull_request.url "$GITHUB_EVENT_PATH")</code></pre><p><strong>Another snag I hit</strong> was that I was testing the approvals action, and I can't approve my own work, so I had to make another account to approve it. Would be nice to have a flag saying "can approve own work", even if it's off by default, and has a big warning. Maybe it is there if I paid Github some money.</p><p><strong>Overall</strong>, it was really easy, and now I need to think of other things to use Actions for. </p><p>One of the main missing bits I'd like to know - it might be there - is how I'd apply this to all (or a wide subset) of our repos without putting a <code>main.workflow</code> in each one, and having to maintain it - could I apply it at the org level somehow? Sort of like how webhooks are also done at an org level.</p><p>This is also quite many-repo specific. We tend to use a mono-repo pattern (one repo with many services, in their own folders). We could have a load of <code>.workflow</code> files, and just check the path in a starting step, but still, it would be nice to be able to iterate down N levels (N = 2 for us - <code>services/NAME/.github</code> would do) and have changes below there, trigger just those workflows.</p><hr><p>The code for this is on github <a href="https://github.com/nicwise/actions-test">nicwise/actions-test</a>. Most of it is bastardised off Jess' blog post, so I can't really claim much originality on it.</p>]]></content:encoded></item><item><title><![CDATA[Upgrading Sonoff Switches with Tasmota]]></title><description><![CDATA[<p><a href="https://fastchicken.co.nz/2018/06/24/more-iot-switch-fun-with-sonoff-and-tasmota/">As I've written before</a>, I have a few of the <a href="https://www.itead.cc/smart-home/sonoff-th.html">16A Sonoff TH16 switches</a> around the place, running the pump, some lights in the bedroom, and as an over-engineered temperature sensor for the spa.</p><blockquote>Sadly, the current default firmware that comes with the Sonoff switches no longer allows OTA firmware</blockquote>]]></description><link>https://fastchicken.co.nz/2019/01/13/upgrading-sonoff/</link><guid isPermaLink="false">5c3a95798fe5395d9c8e5e07</guid><dc:creator><![CDATA[Nic Wise]]></dc:creator><pubDate>Sun, 13 Jan 2019 02:05:05 GMT</pubDate><content:encoded><![CDATA[<p><a href="https://fastchicken.co.nz/2018/06/24/more-iot-switch-fun-with-sonoff-and-tasmota/">As I've written before</a>, I have a few of the <a href="https://www.itead.cc/smart-home/sonoff-th.html">16A Sonoff TH16 switches</a> around the place, running the pump, some lights in the bedroom, and as an over-engineered temperature sensor for the spa.</p><blockquote>Sadly, the current default firmware that comes with the Sonoff switches no longer allows OTA firmware upgrades, so you have to do it with a serial adapter. I got mine from SparkFun, which took AGES to get here, but works perfectly. Just make sure it's 3.3v not 5 (most can do both). Takes about the same amount of time as OTA.</blockquote><p>These are super cheap, and so far, very robust and useful. The firmware they come with, tho, needs a cloud connection, and doesn't work with <a href="https://github.com/nfarina/homebridge">Homebridge</a>. Enter the <a href="https://github.com/arendst/Sonoff-Tasmota">Tasmota firmware</a>, which makes them into MQTT generating, Wemo-compatible super switches. So far, so good.</p><p>Installing the firmware isn't too bad, with a Mac. <a href="https://github.com/mirko/SonOTA">SonOTA</a> fixes that, and loads up the current latest firmware.</p><p>But after that, you're on your own. The firmware has a few options: you can use a URL to load the firmware, or you can download it and use your browser to upload the firmware, and the <a href="https://github.com/arendst/Sonoff-Tasmota/wiki/Upgrade#firmware-binary-sources">SonOTA page has a link to the latest version of the firmware</a>.</p><p>There is a catch on the internet-site-update tho: you need a decent WIFI signal (75% or better?), or it'll just refuse to load. All my devices are quite a way away from the access point, and well below 75%.</p><p>Also, if there isn't enough space for the full firmware - and normally, there isn't - you need to get and <strong>install the minimal version first,</strong> then <strong>install the normal version</strong>. I didn't find this part obvious at all, but <strong>that's the critical step</strong>. (also, this is all on a publicly editing Wiki page, so now, I've edited it)</p><p>To be fair, the page does say you have to do this - but they talk about how to do it with a <code>#define MINIMAL</code> - no mention of what to do if you're using the pre-built ones.</p>]]></content:encoded></item><item><title><![CDATA[John William Wise - 1936-2018]]></title><description><![CDATA[<p><strong>John William Wise</strong> was born the middle child of 3, in a small village called Nunthorpe, North Yorkshire, in July 1936, 3 years before the end of World War II. His father - also John William - was a farm labourer, and his mother was a post office worker in</p>]]></description><link>https://fastchicken.co.nz/2019/01/06/john-william-wise-1936-2018/</link><guid isPermaLink="false">5c2ed7a7d293b03724eae213</guid><dc:creator><![CDATA[Nic Wise]]></dc:creator><pubDate>Sun, 06 Jan 2019 07:46:44 GMT</pubDate><media:content url="https://fastchicken.co.nz/content/images/2019/01/JohnWise025-1.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://fastchicken.co.nz/content/images/2019/01/JohnWise025-1.jpg" alt="John William Wise - 1936-2018"><p><strong>John William Wise</strong> was born the middle child of 3, in a small village called Nunthorpe, North Yorkshire, in July 1936, 3 years before the end of World War II. His father - also John William - was a farm labourer, and his mother was a post office worker in the nearby village.</p><blockquote>Dad died on November 26th, 2018. This is the eulogy I wrote for the funeral gathering, and some of the photos we "found".</blockquote><p>He went to a small 3 classroom school, situated by the local parish church, where he was a choirboy, tho I can’t say we heard any proof of angelic singing around the house.</p><p>In his early life, everything and everyone was close and familiar, across all aspects of life. But at the same time, everyone knew their place, and what their likely path in life was going to be. The nearest suburban area was <a href="https://www.google.com/maps/search/middlesbrough/@54.5340773,-1.2086139,12.76z">Middlesbrough</a>, where the iron and steel industry dominated the employment landscape. <a href="https://en.wikipedia.org/wiki/Auckland_Harbour_Bridge#Initial_structure">Auckland Harbour Bridge was one of the projects that used Middlesbrough steel</a>.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/01/JohnWise005.jpg" class="kg-image" alt="John William Wise - 1936-2018"><figcaption>My grandparents + Dad</figcaption></figure><p>Parts of Nunthorpe housed the captains of the local industry, and one of John’s youthful tasks was to walk across the fields to take milk, in a can, to Lady Dorman, who often received only half of what was expected - not because he drunk it - he hated milk, unless it was ice cream or cheese - but because he would swing the can round as he walked.</p><p>As well as his love of sweet things, he loved simple foods, and his other trick was to eat out the middle of the loaf of bread he was sent to buy, made easier if the fresh bread was tucked into his jacket to keep warm.</p><hr><p>He enjoyed a simple, close-knit community, where the whole village would turn out on summer days to watch the village cricket matches. At 13 he passed a scholarship to Eston Technical Collage, which involved 2 long bus trips, but came with an exposure to the wider world. He was head boy in his last year, his school report showing great improvement - except for divinity studies. He never was one for that.</p><p>The best part of being the head boy was being in charge of the tuck shop. I’m pretty sure he would have enjoyed that.</p><p>In keeping with with his early upbringing, he chose an apprenticeship as an agricultural fitter, and as the firm he worked for was a fair distance from his home, he acquired his first vehicle, a 350 BSA motorbike.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/01/JohnWise002.jpg" class="kg-image" alt="John William Wise - 1936-2018"><figcaption>He's the right of the two lads at the bottom.</figcaption></figure><p>He and mum met when he was 20, in a park. He and his village mates had travelled from their country village to a pub on the edge of Middlesbrough, where the innocent youth of the Methodist Church had gone for an evening walk after attending the service.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/01/JohnWise008-1.jpg" class="kg-image" alt="John William Wise - 1936-2018"><figcaption>Not sure when this was taken - mid-50's at a guess. They were either just married, or just about to be.</figcaption></figure><p>It wasn’t meant to be a pick up job - and there definitely wasn’t Tinder back then - one of the village woman also attended the church Mum went to, and had a thing for the vicar, who tended to the 4 local methodist churches, including Mum’s local church.</p><p>There were further liaisons with these two groups, including bus trips to Christmas pantos and summer outdoor theatre in seaside resorts.</p><p>It was there that Mum and Dad became a pair, which resulted in 62 years of union, and 56 years of marriage.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/01/JohnWise043.jpg" class="kg-image" alt="John William Wise - 1936-2018"><figcaption>Top of Panakiri Bluff, Waikaremoana, Te Urawera.</figcaption></figure><hr><p>After a few years of courtship, they agreed to make the trip to New Zealand and a lifetime of adventure. They chose New Zealand because Mum’s uncle had settled here 40 years before, in 1922, and Mum’s brothers Eric and Harry had both served time in New Zealand waters as members of the Merchant Navy, and it came highly recommended.</p><p>And what an adventure it became, with so many places to explore.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/01/IMG_0022.jpg" class="kg-image" alt="John William Wise - 1936-2018"><figcaption>3 months around the South Island before I started school - around 1979.</figcaption></figure><p>They managed to cover almost every part of New Zealand, except Stewart Island, with several long trips in the South Island, and even when I popped in, it didn’t stop them - they took me on my first tramp to the Kitekite Falls in Piha at 6 weeks old.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/01/IMG_0019.jpg" class="kg-image" alt="John William Wise - 1936-2018"><figcaption>We did this. A lot.</figcaption></figure><p>Sure, I grumbled “how much further” and “are we there yet”, but Dad helped me on many journeys with his made up stories and it was always worthwhile to get to the top of the mountain or the hut at the end of the day. Sadly, I can’t remember the exact words, but there was one about Bee Pee - something about how bee’s make cars go - and a story about how Waikaremoana got its name, which was about a local chief complaining that he had to carry his daughter, Moana.</p><p>And then there was being carried down from Ketetahi Hut, in exchange for agreeing to carry him up when he’s 80. It’s a coupe of years late, but we’re going to do that just before Christmas.</p><figure class="kg-card kg-image-card kg-width-full kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/01/pano1-1.jpg" class="kg-image" alt="John William Wise - 1936-2018"><figcaption>Not a bad view</figcaption></figure><figure class="kg-card kg-image-card kg-width-full kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/01/pano2.jpg" class="kg-image" alt="John William Wise - 1936-2018"><figcaption>... a bit to the left ...</figcaption></figure><p>Most of you are aware of all of these adventures, having being a part of our lives since. The long list of places I’ve been in this country, mostly with my parents, are something I’m proud of, and still places I love going.</p><hr><p>For me, Dad was always there and always supportive, be it cricket, badminton, or being picked up from the various sports and, er, recreations that a teenager gets up to. There was never any question about getting a lift back from a party, even if I’d had a bit much to drink, and dropping of a few friends on the way.</p><p>I’d spend school holiday summers helping him with the lawns, paid with the accumulated change in his cap on the dashboard, and we’d have Bundaberg ginger beer, sandwiches from the bakery, and Earnest Adams slice for lunch.</p><p>Oh, and the odd secret ice cream. Don’t tell Mum.</p><hr><p>Mum and Dad were opposites, but complementary, and Dad was forever supportive of her schemes - a dibbler here, a wooden bowl there, a set of tea light candle holders or placemats, and a threaded carpet or 3.</p><p>Just as he’d been mentored growing up, he was happy to pass his knowledge of gardening and motor mowers on to others. He was always generous with his time.</p><p>But as time went on, his body started to fail him. About a month ago, the blade on the mower gave up, and what would normally have been an hour long job, took all day, and exacerbated the physical problems he had. The last straw came 2 days before he died, when another part came off while mum was mowing the lawn, and he had to reluctantly concede that it had to go into the repair shop - something he’d done his whole life now eluded him.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/01/JohnWise016.jpg" class="kg-image" alt="John William Wise - 1936-2018"><figcaption>Red Crater</figcaption></figure><p>He had and cooked a good breakfast on Sunday - eggs, bacon, black pudding, which was surprising as he’d not been eating a lot - but after Mum came back from a walk he was not well, having developed a fever, and decided to go to Middlemore of his own accord, where he died that night.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/01/IMG_0026.jpg" class="kg-image" alt="John William Wise - 1936-2018"><figcaption>The 70's were a hell of a decade...</figcaption></figure><hr><p>There is a lot I’ve learned writing this - about his early life and their life together. Things I didn’t know and things I hadn’t taken the time to learn. He taught me a lot, directly and indirectly, and while he’ll always be with me, I’ll always miss him, too.</p><p><strong>Ka kite anō au i a koe. I’ll see you again.</strong></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://fastchicken.co.nz/content/images/2019/01/final-vista.jpg" class="kg-image" alt="John William Wise - 1936-2018"><figcaption>His final vista. Not a bad view.</figcaption></figure>]]></content:encoded></item><item><title><![CDATA[Running Docker on the home server - giving life to old hardware]]></title><description><![CDATA[<p>Sometimes, old hardware lasts a very very long time. Until recently, I had an iPhone 7, which was mostly perfect running iOS 12 - the battery could be better, but in general it was good. I upgraded to an 8 recently, but mostly for the battery and because work (who</p>]]></description><link>https://fastchicken.co.nz/2018/11/25/running-docker-on-the-home-server-giving-life-to-old-hardware/</link><guid isPermaLink="false">5bfa5a72ef33f60f04f55b08</guid><dc:creator><![CDATA[Nic Wise]]></dc:creator><pubDate>Sun, 25 Nov 2018 08:18:21 GMT</pubDate><content:encoded><![CDATA[<p>Sometimes, old hardware lasts a very very long time. Until recently, I had an iPhone 7, which was mostly perfect running iOS 12 - the battery could be better, but in general it was good. I upgraded to an 8 recently, but mostly for the battery and because work (who provides my phone) had a spare one in the cupboard.</p><p>In 2008, I left the BBC, and started working from home in London, for a friend in Denmark. We were doing email archiving - very much like AfterMail, where I met him - so I needed a machine which I could run Exchange and Active Directory on. So I got a well spec’ed (for the time) Mac Mini - Core 2 Duo, 500GB disk, 8GB RAM (the most it could take). It served me as a VMWare Fusion server for the 9 months or so I worked for them.</p><p>Since then, it’s been used for various things, mostly as a iTunes server, serving media to the Apple TV, or to store our music collection. Over the years, I changed out the DVD drive and hard drive for a 256GB SSD, and a 500GB SSHD which I had spare. The SSD gave the old machine a big boost in performance.</p><p>With the advent of Docker, I started to run various services on it, mostly to learn about how it worked. After a while I ran into some Mac-specific issues, so I fired up Virtual Box and ran Linux in the VM, with Docker containers inside that.</p><p>While that worked, I was basically not using the Mac for anything, so I switched out the OS to Ubuntu 18.04 (the current LTS) and ran the Docker containers on the bare metal. The hardest bit of the upgrade was finding a monitor (in this case, our TV) to do the install with. Once it’s installed, it just lives on the network, in the loft in the studio, next to the NAS and the UPS.</p><p>Low maintenance and extreme ROI doesn’t even come close to what I’d had out of this little machine. It’s been fantastic.</p><p>So my setup out there is the Mac Mini and a Synology DS418j with 4x 4TB of disk (12TB usable). The Mini does most of the compute work, and the NAS provides the disk and a few other bits.</p><h3 id="why-would-i-want-to-do-this">Why would I want to do this?</h3><p>Mostly, it’s fun! I use Docker a lot at work, in various forms, so putting things in containers at home is a logical extension of that - it just makes sense to containerise all the things.</p><p>The concept of containers makes it really easy to package up something - anything from a full working application like Homebridge, to a single shell script - and run it in its own space, so that the underlying OS is none the wiser.</p><h3 id="what-would-i-change-or-add-if-i-had-to-could">What would I change or add if I had to / could</h3><p>Let’s say the Mac Mini dies and I have a bunch of spare cash around. Most likely, I’d get an equivalently small WinTel Box, and run Linux on it again. Maybe I’d get one of the newer / more powerful Synology NAS with x86, and run containers on that.</p><p>Most likely, I’d not buy another Mac Mini, but only because the new ones are overpriced unless you want to run macOS - there are a lot more powerful intel machines out there if you just want to run Linux - Intel NUC’s being one of them. I’d get a 32GB NUC with 4-6 cores, I think.</p><p>So far, tho, this machine has been rock solid. It’s 10 years old, and there is no reason to shelve it.</p><p>I’d also love some kind of orchestration tool - something like a very very light version of Kube. The Mini could run Kube, I think, but it’s overkill for what I’m using. I would like some way to build a container locally on my laptop, push it to the repository, then run an API command to restart the running container with the new image. I have this “working” using <code>make</code> and <code>bash</code>, but it’s no ECS or Kube. Maybe that’s something I can do later.</p><p>I’d also add a build system, which monitored a git repository, and rebuilt containers based on git commits. I could run <a href="https://concourse-ci.org/">Concourse</a> on this, which we use at work, but again, I do maybe 1 or 2 container builds a <em>month</em>, so that is overkill. I think there is enough resource to do it, but I now have a registry on the Mini, so that I can build on my (relatively) fast laptop, and then push the resulting container, rather than using the (relatively) slow Mini to do the builds.</p><h3 id="what-sort-of-resources-am-i-using-for-this">What sort of resources am I using for this?</h3><p>I have the basic Mini, with 8GB of RAM. It’s running Ubuntu 18.04, and it’s using about 1.5GB of RAM, with about 6GB used as cache. A similar spec NUC would be about $400 NZD.</p><pre><code>top - 05:37:07 up 1 day,  9:10,  2 users,  load average: 0.06, 0.13, 0.13
Tasks: 197 total,   1 running, 142 sleeping,   0 stopped,   0 zombie
%Cpu(s):  2.7 us,  2.5 sy,  0.0 ni, 94.5 id,  0.2 wa,  0.0 hi,  0.2 si,  0.0 st
KiB Mem :  7907236 total,  1431748 free,  1244500 used,  5230988 buff/cache
KiB Swap:  4194300 total,  4194300 free,        0 used.  6465064 avail Mem 
</code></pre><p>The main installed software on here is <a href="https://docs.docker.com/install/linux/docker-ce/ubuntu/#install-using-the-repository">Docker</a> - there isn’t much else installed.</p><pre><code>
# install supporting stuff
sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    software-properties-common

# install GPG keys for docker
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

# add the x86 repo
sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

# update 
sudo apt-get update

# install docker-ce
sudo apt-get install docker-ce

# make sure the ubuntu user can use the docker command 
sudo usermod -aG docker ubuntu

# test it with hello-world
sudo docker run hello-world

# turn it on, so it comes up on boot.
sudo systemctl enable docker

</code></pre><p>The OS is out of the box Ubuntu 18.04, the current LTS version. It’s not overly exciting, and I’m sure I could get a more paired-down OS, but this works for me, as I’m very comfortable with Ubuntu. If I was doing this in the cloud, I’d be using Amazon Linux 2 - I tried for this, but it’s VM or Cloud only.</p><p>The Mini also has a 500GB SSHD mounted on <code>/mnt/data</code>, but I have 200GB free on the 256GB SSD so I’ve got no reason to use it, and no inclination to take the machine apart to remove it.</p><p>I could use it as backup, I guess.</p><h2 id="things-to-run-on-a-10-year-old-machine">Things to run on a 10 year old machine</h2><p>There are some things that are good to run on this machine, and some things which it’s totally unsuitable for. Transcoding or anything like that is useless - it doesn’t have the cores or the grunt to do it. But there is plenty of other things it can do.</p><h3 id="unms">UNMS</h3><p><a href="https://unms.com/">UNMS is the Ubiquity Network Management System</a> - UBNT’s free management tool designed for people running wide area ISP networks based around their routers and WIFI gear.</p><p>For me, it also works to “manage” the Edgerouter X ($99 NZD)  I have as a route/gateway for my fibre connection. Like most things in this setup, its total overkill, but it was fun to setup and play with.</p><p>Ideally, I’d replace my wifi kit with Ubiquity Unifi gear, or maybe Amplify, but the combination of the Edgerouter X and some older Apple Airport Extremes has proven to work great. Eventually, I’ll need to revisit this when some of this gear dies - but again, 6 year old gear is still doing strong, and I don’t need to replace it yet.</p><p>Installing UNMS is easy, tho it’s a case of <code>curl | sh</code>, which has serious security implications (lets download and run a script from the internet!).  I trust Ubiquity in this case, but there is lots out there I don’t.</p><p>UNMS makes its own user, and uses <code>docker-compose</code> to setup the various containers it uses, including postgres, rabbitmq, fluent, redis, netflow and nginx.</p><p>If I was running a wireless ISP, it’d be awesome, but as it is, it’s a nice way to manage the router.</p><h3 id="plex">Plex</h3><p><a href="https://plex.tv">Plex</a> is the godfather of media servers, coming from the now ancient Xbox Media Center (XBMC). It’s a very full featured media centre, and can serve media to multiple clients, including our Apple TV, iOS devices, as well as other devices outside the network.</p><p>Plex is a fairly decent investment to get running, but the container helps a lot - mostly you just need to get the command line settings right. The provided base container - <code>plexinc/pms-docker</code> - works great out of the box.</p><p>I store the media on the NAS, and serve it to the Mac Mini over NFS, so it’s looking at a local folder. Transcoding anything is slow, so I have all the clients set to stream (maximum bitrate). This seams counter intuitive, but it works. Even with a few devices running, the Mini is barely breaking 10% CPU, as it’s mostly just moving bits around on the network.</p><p>It’s running in <code>-net=host</code> mode, which isn’t ideal, but the other option is fixing ports, which I don’t want to do.</p><p>I bought a Plex Pass, but I’m not sure if I need it for this. $40/year wasn’t bad, given we use it almost every day.</p><pre><code>docker pull plexinc/pms-docker:latest

docker run \
    --restart=always \
    -d \
    --name plex \
    --network=host \
    -e TZ="Pacific/Auckland" \
    -e PLEX_CLAIM="claim-nnnnnnn" \
    -v ~/plex/config:/config \
    -v ~/plex/transcode:/transcode \
    -v ~/plex/media:/data \
    plexinc/pms-docker:latest
</code></pre><h3 id="homebridge">Homebridge</h3><p><a href="https://github.com/nfarina/homebridge">Homebridge</a> is a node-based hub for Homekit, so you can use Siri and Home.app to control various non-homekit things around the house. I’ve written about it a number of times before</p><ul><li><a href="https://fastchicken.co.nz/2016/01/11/homebridge-homekit-without-homekit-hardware/">Homebridge - Homekit without Homekit hardware</a></li><li><a href="https://fastchicken.co.nz/2017/06/25/more-homebridge-aws-iot-dash-button-sqs-broadlink-rm3-mini/">More Homebridge - AWS IOT, Dash Buttons, SQS, Broadlink RM3 Mini</a></li><li><a href="https://fastchicken.co.nz/2018/06/24/more-iot-switch-fun-with-sonoff-and-tasmota/">More IOT switch fun with Sonoff and Transmota</a></li></ul><p>For this, I built my own container. There might be workable ones out there now, but there wasn’t when I started. It used to rely on the server having local services available, but I appear to have installed everything inside the container - <code>avathi</code>, <code>libmds</code> and others. You also have to use <code>—net=host</code> to get this working, which is a bit yucky, but <code>mdns</code> wants to control a lot of stuff.</p><p>I have various components installed for the switches and things around the house<br>* Wemo (I have 4 switches)<br>* Broadlink RM (I have 2 Broadlink RM Mini RF emitters to control our heating)<br>* Tasmota Switches to control the Sonoff switches, which have the Tasmota alternative firmware. This communicates via MQTT, provided by Mosquito. This controls the outside tank pump (plus outside temperature/humidity), the spa temperature (but not the spa pump or heater, sadly), and some lights in the bedroom (plus temperature and humidity, as that room gets very humid and damp)<br>* A temperature and humidity plugin which reads from MQTT and provides the values to Homekit.<br>* My own plugin - <code>https://github.com/nicwise/homebridge-platform-sqs</code>  - which listens on an SQS queue, and toggles a switch when a messages comes in. I use this with <a href="https://fastchicken.co.nz/2017/06/25/more-homebridge-aws-iot-dash-button-sqs-broadlink-rm3-mini/">a  pair of Amazon Dash Buttons</a> which control the outside (Spa) lights and the heating (on @ 20 degrees, and off)</p><p>Mostly, I use this as a big, fairly intelligent scheduler. I detest Siri, so there is no “Siri, turn the lights on”, tho that does work.</p><h3 id="nginx-frontend-to-all-the-things">Nginx - frontend to all the things</h3><p>Nginx is now my HTTPS server of choice, as it’s very easy to setup and very very performant. I have it controlling port 80 and 443, and then proxying to other containers which want to listen on those standard ports.</p><p>It also handles SSL termination, so I can run Let’s Encrypt certificates locally - HTTPS all the things. It handles frontend services for<br>* s3.home.local -&gt; Minio<br>* terraform.home.local -&gt; Anthology<br>* unms.home.local -&gt; UNMS (including websockets)<br>* docker.home.local -&gt; docker registry<br>* Anything else I care to want to run, which wants to be on it’s own hostname + port 443</p><p>DNS names provided by the router (static host names), however I’d prefer to use <a href="https://pi-hole.net/">pihole</a> - I’ve just not managed to get that working yet.</p><p>Protip: Make sure you don’t take nginx down before pulling the latest image from the registry, as the registry is fronted by … nginx!</p><h3 id="anthology-terraform-registry">Anthology - Terraform registry</h3><p>Anthology is a basic <a href="https://terraform.io">Terraform</a> registry, which is where you can store Terraform modules. You don’t need to use this to use Terraform, but it was something I wanted to play around with. I use Terraform for everything at work, and all my personal AWS infrastructure - the host this blog is on, plus a few others, DNS, cloudfront etc - is all setup using Terraform.</p><p>Anthology backends on to S3, which I’ve used Minio for locally. Minio lets you set an Access Key and Secret, so as long as the one in Minio and the one here match, you’re good to go.</p><p>I still don’t have a good way to upload to a registry, or manage the content. The official one backs onto Github, but I think I need to write something which packages locally and pushes to S3, and there doesn’t appear to be anything around yet which does that. It’s not hard to do in bash tho, just not very repeatable.</p><pre><code>docker pull erikvanbrakel/anthology 

docker run -d --restart=always \
  --name anthology -p 7080:7080 \
  -e "AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE" \
  -e "AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \
  --dns=192.168.1.1 \
  erikvanbrakel/anthology   --port=7080 \
  --backend=s3 \
  --s3.bucket=anthology \
  --s3.endpoint=https://s3.home.local
</code></pre><h3 id="minio-local-s3">Minio - local S3</h3><p>Minio is a local server which exposes an API identical to the AWS S3 APIs, to a high level of detail. It can support multi-server, redundancy, mirroring and a load of other stuff. You could run a cloud storage business off this software - I just use it as a dumb blob store.</p><p>I use the default container, and point it at the local file system to store it’s files. The Access Key and Secret and just random bits which have to match up with whatever client (Anthgology) you are using.</p><pre><code>docker pull minio/minio

docker run -d --restart=always \
  -p 7180:9000 --name minio \
  -v /home/ubuntu/minio/data:/data:rw \
  -v /home/ubuntu/minio/config:/root/.minio:rw \
  -e "MINIO_ACCESS_KEY=AKIAIOSFODNN7EXAMPLE" \
  -e "MINIO_SECRET_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \
  minio/minio server /data
</code></pre><h3 id="docker-registry">Docker Registry</h3><p>This provides a local version of the <a href="https://hub.docker.com/_/registry/">Docker Registry</a>, which is sort of the non-UI version of Docker Hub. Again I’m using the official container - <code>registry</code> - as I trust Docker to provide something which is secure and patched.</p><p>I backend this on the local file system, tho the NAS would be just as good. I did have to make sure that Nginx allowed larger file uploads for this tho - some of the container layers can get quite large, 350MB isn’t uncommon for something with Ubuntu in it!</p><p>Thats fairly easy with nginx tho:</p><pre><code>server {
    listen 80 http2;
    listen 443 ssl http2;

    server_name   docker.home.local;

    include /etc/nginx/conf.d/ssl.conf;

    client_max_body_size 500M; &lt;-------

    location / {
        proxy_pass         http://docker;
        proxy_http_version 1.1;
        proxy_set_header   Connection keep-alive;
  ...
</code></pre><pre><code>docker pull registry

docker run \
  -d --restart=always \
  -p 7181:5000 --name registry \
  -v /home/ubuntu/registry:/var/lib/registry \
  registry
</code></pre><p>Once this is up, you can just tag your images using the hostname, and push to it., then pull from it Easy.</p><pre><code>docker build . -t docker.home.local/homebridge
docker push docker.home.local/homebridge
...
docker pull docker.home.local/homebridge
docker run docker.home.local/homebridge
</code></pre><h3 id="mosquitto">Mosquitto</h3><p><a href="https://mosquitto.org/">Mosquito</a> is a local MQTT broker I use for the Tasmota / Sonoff Switches. I didn’t do much to set this up, and <a href="https://fastchicken.co.nz/2018/06/24/more-iot-switch-fun-with-sonoff-and-tasmota/">most of it is documented here</a>.</p><p>Again, I’m using the provided <code>eclipse-mosquitto</code> container</p><pre><code>docker pull eclipse-mosquitto:latest

docker run \
    -d —restart=always \
    —name mosquitto \
    -p 1883:1883 -p 9001:9001 \
    -v /home/ubuntu/mosquitto:/mosquitto:rw \
    eclipse-mosquitto:latest
</code></pre><p>Most likely, you want to set it up with the username + password. That is on my to do list, as this is all local on my internal network.</p><h3 id="some-of-my-own-ones">Some of my own ones</h3><ul><li><em>Copy Media</em> - just runs every 5 mins, looks for a specific file extension in a folder, and moves them somewhere else if it finds them. It’s basically a bash script, in a container, fired by cron.</li><li><em>Certs</em> - refreshes the local <code>*.home.local</code>  SSL certificate with Lets Encrypt using DNS as the source of truth, and pushes it to the various local places I need it. I have to do this every 3 months, so it’s important that it’s easy, bullet proof, and somewhat automated. So, like a good SRE, I put it in a container and wrote a runbook ;-)</li></ul><h3 id="other-things">Other things</h3><p>I’m thinking about dumping Bitbucket and putting <a href="https://docs.gitlab.com/omnibus/docker/">Gitlab</a> - in a container - on the Mini. That would definitely be backed onto the NAS (or backed up onto the NAS). I’ve not had a problem with bitbucket, bit it’s one less thing to have out there in the cloud. That does mean I need to be on the VPN to get to my repo, but most of the time, thats not an issue. Not sure how I do it for remote builds like codebuild, which I use to build and deploy some lambdas in AWS - maybe I can use bitbucket as a mirror.</p><h2 id="there-s-life-left-in-the-ol-girl-">There’s life left in the ol’ girl!</h2><p>OK, thats usually a reference to a boat (or a spaceship), but there’s definitely life left in this old Mac Mini, and while it’s not really stretched with what I’m doing with it, it’s still providing a lot of value even after 10 years. I don’t need a super-powerful server at home - there’s only three of us, and the cat has very low computing requirements.</p><p>Docker and containers are a technology that is not going away any time soon, especially when you think that “serverless” is really just “containers with hosts you don’t manage, and a great lifecycle story”. Knowing how containers work, and running them for real, is a very useful skill and knowledge to have. Even if “real” is just a few things to play around with at home. It’s a skill that I think every developer needs to be exposed to now - it’s not optional.  And mostly, it’s fun.</p>]]></content:encoded></item><item><title><![CDATA[More IoT switch fun with Sonoff and Tasmota]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>I was looking at <a href="https://tomasmcguinness.com/">Tomas Blog</a> a while ago, when he mentioned that he had bought a couple of the <a href="https://www.itead.cc/smart-home.html">Sonoff WIFI switches</a> to do some outdoor LED lighting.</p>
<blockquote>
<p>Sadly, the current default firmware that comes with the Sonoff switches no longer allows OTA firmware upgrades, so you have to</p></blockquote>]]></description><link>https://fastchicken.co.nz/2018/06/24/more-iot-switch-fun-with-sonoff-and-tasmota/</link><guid isPermaLink="false">5b2eb4cab52b40059b5780c9</guid><dc:creator><![CDATA[Nic Wise]]></dc:creator><pubDate>Sun, 24 Jun 2018 06:43:48 GMT</pubDate><media:content url="https://fastchicken.co.nz/content/images/2018/06/header.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://fastchicken.co.nz/content/images/2018/06/header.jpg" alt="More IoT switch fun with Sonoff and Tasmota"><p>I was looking at <a href="https://tomasmcguinness.com/">Tomas Blog</a> a while ago, when he mentioned that he had bought a couple of the <a href="https://www.itead.cc/smart-home.html">Sonoff WIFI switches</a> to do some outdoor LED lighting.</p>
<blockquote>
<p>Sadly, the current default firmware that comes with the Sonoff switches no longer allows OTA firmware upgrades, so you have to do it with a serial adapter. I got mine from SparkFun, which took AGES to get here, but works perfectly. Just make sure it's 3.3v not 5 (most can do both). Takes about the same amount of time as OTA.</p>
</blockquote>
<p>They sounded like they were quite good, and fairly cheap, too. I already have a few Wemo switches, which are very good so far, as well as a few other bits, but I specifically wanted something to control the spa, which has a simple time-based on/off timer.</p>
<p>Problem is, it's running a heater and a pump, so the draw is rather more than the 2.4kw that a 10A Wemo can handle - it needs at least 16A.</p>
<p><img src="https://fastchicken.co.nz/content/images/2018/06/Screen-Shot-2018-06-24-at-16.34.46.png" alt="More IoT switch fun with Sonoff and Tasmota"></p>
<p>Doing a bit of a google around for something else, I found that Sonoff have a 16A switch - the TH16 - which is what I need for the spa. Conveniently, it also comes with a waterproof thermometer. So I <a href="https://www.aliexpress.com/item/Sonoff-TH16-16A-Wifi-Smart-Switch-Support-Temperature-Monitor-Sensor-Humidity-High-Accuracy-Sensor-Work-with/32825049053.html?spm=a2g0s.9042311.0.0.63114c4dV1aAj0">picked one up from AliExpress for $11</a> + a <a href="https://www.aliexpress.com/item/Original-Sonoff-AM2301-Temperature-Humidity-Sensor-DS1820-Temperature-Probe-Sensor-High-Accuracy-for-Sonoff-TH10-and/32819337421.html?spm=a2g0s.9042311.0.0.63114c4dV1aAj0">waterproof temperature sensor</a> and <a href="https://www.aliexpress.com/item/Original-Sonoff-AM2301-Temperature-Humidity-Sensor-DS1820-Temperature-Probe-Sensor-High-Accuracy-for-Sonoff-TH10-and/32819337421.html?spm=a2g0s.9042311.0.0.63114c4dV1aAj0">temperature+humidity sensor</a>. Not bad for $20.</p>
<hr>
<p>Last week, they turned up - turns out Ali Express is quite quick, sometimes. I grabbed a spare, old extension lead, stripped it back, and wired it up - the TG16 doesn't have a normal plug, just terminals which you can connect wires to.</p>
<p>Once it was wired up, I plugged it in, grabbed their app, and gave it a try. It worked pretty well out of the box with usual flow - SSID, password, username and password.....</p>
<p>.... <strong>wait a moment</strong>. It appears these will only work with an internet connection, and they have to talk via the ITEAD/Sonoff cloud service. So yeah. Someone else, out there, has direct access to turning things on and off. And if they go away, all my devices stop working.</p>
<p>While there does appear to be <a href="https://github.com/gbro115/homebridge-ewelink">a homebridge plugin</a> which will use it, I don't really like this model very much. Plus their app is a bit naff.</p>
<p>I had a look around at other stuff - I can run a <a href="https://github.com/vponomarev/Sonoff-Server">local</a> <a href="https://github.com/mdopp/simple-sonoff-server">server</a>, sort of. But they can also be reflashed with an open source firmware called <a href="https://github.com/arendst/Sonoff-Tasmota">Tasmota</a>, which supports HTTP, MQTT, all the sensors, and doesn't need to communicate out at all.</p>
<p>Sounds good.</p>
<p>Only problem is, normally you have to break them open and plug in a serial port thing. Rather beyond my electronics skill level.</p>
<p>Then I came across <a href="https://github.com/mirko/SonOTA">SonOTA</a>, which is a python app which does the various steps to do a local over-the-air (OTA) firmware upgrade - adding the device to the local wifi, loading the updated firmware, rebooting etc. Once it's done (about 5 mins or so), you get the basic, but very functional, Tasmota interface.</p>
<p><img src="https://fastchicken.co.nz/content/images/2018/06/Screen-Shot-2018-06-24-at-17.37.01-1.png" alt="More IoT switch fun with Sonoff and Tasmota"></p>
<blockquote>
<p>Note that for one of the switches, the very basic one, iTEAD have prevented OTA upgrades. Not good :(</p>
</blockquote>
<p>The steps are pretty simple. Turn off your local firewall (as they listen to a few ports during the process), make sure you have only one network connection, then run <code>python3 sonota.py</code> and follow the prompts.</p>
<p>After a few reboots, and a check of the router to work out the IP, I'm into the new interface. It has a load of settings, but the main ones I want are the sensor (Configuration -&gt; Module -&gt; Set it as a TH16, and add the <em>correct</em> type of sensor in the gpio14 dropdown), and the MQTT configuration.</p>
<p><img src="https://fastchicken.co.nz/content/images/2018/06/Screen-Shot-2018-06-24-at-17.40.24.png" alt="More IoT switch fun with Sonoff and Tasmota"> <img src="https://fastchicken.co.nz/content/images/2018/06/Screen-Shot-2018-06-24-at-17.40.42.png" alt="More IoT switch fun with Sonoff and Tasmota"></p>
<hr>
<p>Next step is a <a href="https://en.wikipedia.org/wiki/MQTT">MQTT</a> broker. This is kind of like a message queue, but designed for IoT stuff. It works over HTTP and websockets, so the clients can be very low powered and uncomplicated, and have the broker handle most of the rest of the communications, polling etc. It's also an open standard, so lots of systems support it, including AWS.</p>
<p>I googled around a bit, again, and found <a href="https://mosquitto.org/">Mosquitto</a>, which is from Eclipse. They have a basic <a href="https://github.com/eclipse/mosquitto/tree/master/docker/1.4.14">Docker container</a>, which I modified to use 1.4.15 and also to set the directories and permissions in the startup script.</p>
<p>Once that was up, I could see in the logs that the switch was talking to server. Now for the other end of the connection.</p>
<blockquote>
<p>Side note: I didn't bother setting up a username+password in mosquitto. I'll most likely do it in the future, but the machine isn't on the internet, and never will be, so until I get all of this sorted out, I'm ok with no username + password. But it can and does support authentication, and you should use it.</p>
</blockquote>
<hr>
<p>The last step is to get the homebridge side setup. There are a set of plugins which supports the MQTT interface, and they work quite nicely:</p>
<ul>
<li><a href="https://github.com/MacWyznawca/homebridge-mqtt-switch-tasmota">Switch</a></li>
<li><a href="https://github.com/MacWyznawca/homebridge-mqtt-temperature-tasmota">Temperature</a></li>
<li><a href="https://github.com/MacWyznawca/homebridge-mqtt-humidity-tasmota">Humidity</a></li>
</ul>
<p>The configuration is pretty much normal homebridge. Replace your server name, add a username+password if you have one, and rename <code>spaswitch</code> with the topic name of your device. The <code>Name</code> can be anything, that's what shows up in HomeKit.</p>
<pre><code>...
&quot;accessories&quot;:[
{
    &quot;accessory&quot;: &quot;mqtt-switch-tasmota&quot;,

    &quot;name&quot;: &quot;Spa&quot;,

    &quot;url&quot;: &quot;mqtt://(servernamehere)&quot;,
    &quot;username&quot;: &quot;&quot;,
    &quot;password&quot;: &quot;&quot;,

    &quot;topics&quot;: {
        &quot;statusGet&quot;: &quot;stat/spaswitch/POWER&quot;,
        &quot;statusSet&quot;: &quot;cmnd/spaswitch/POWER&quot;
    },
    &quot;manufacturer&quot;: &quot;ITEAD&quot;,
    &quot;model&quot;: &quot;Sonoff TH&quot;
},
{
    &quot;accessory&quot;: &quot;mqtt-temperature-tasmota&quot;,
    
    &quot;name&quot;: &quot;Spa Temperature&quot;,

    &quot;url&quot;: &quot;mqtt://(servernamehere)&quot;,
    &quot;username&quot;: &quot;&quot;,
    &quot;password&quot;: &quot;&quot;,
    
    &quot;topic&quot;: &quot;tele/spaswitch/SENSOR&quot;,
    
    &quot;activityTopic&quot;: &quot;tele/spaswitch/LWT&quot;,
    &quot;activityParameter&quot;: &quot;Online&quot;,
    
    &quot;startCmd&quot;: &quot;cmnd/spaswitch/TelePeriod&quot;,
    &quot;startParameter&quot;: &quot;120&quot;,
    
    &quot;manufacturer&quot;: &quot;ITEAD&quot;,
    &quot;model&quot;: &quot;Sonoff TH&quot;
},
{
    &quot;accessory&quot;: &quot;mqtt-humidity-tasmota&quot;,
    
    &quot;name&quot;: &quot;Spa Humidity&quot;,

    &quot;url&quot;: &quot;mqtt://(servernamehere)&quot;,
    &quot;username&quot;: &quot;&quot;,
    &quot;password&quot;: &quot;&quot;,
    
    &quot;topic&quot;: &quot;tele/spaswitch/SENSOR&quot;,
    
    &quot;activityTopic&quot;: &quot;tele/spaswitch/LWT&quot;,
    &quot;activityParameter&quot;: &quot;Online&quot;,
    
    &quot;startCmd&quot;: &quot;cmnd/sonoff/TelePeriod&quot;,
    &quot;startParameter&quot;: &quot;120&quot;,
    
    &quot;manufacturer&quot;: &quot;ITEAD&quot;,
    &quot;model&quot;: &quot;Sonoff TH&quot;
}
],
...
</code></pre>
<p>There are <a href="https://github.com/MacWyznawca?utf8=%E2%9C%93&amp;tab=repositories&amp;q=homebridge-mqtt&amp;type=&amp;language=">a few other plugins for other bits</a> from the same guy, too. Nicely done <a href="https://github.com/MacWyznawca">Jaromir</a>.</p>
<hr>
<p><img src="https://fastchicken.co.nz/content/images/2018/06/homekit.png" alt="More IoT switch fun with Sonoff and Tasmota"></p>
<p>So now I have the switch and temperature wired up, I just need to wire it into the spa control, which is just an old-skool clock at present, and run the sensor over the edge. It'll also need a splash proof box, which I have spare from another project.</p>
<p>I'm going to wait for that bit until I have more time, incase it goes wrong and I need to wire the old one back in.</p>
<p>I have a few other uses for a temperature meter and switch - keeping the studio above &quot;very cold&quot; for a start. So I'll most likely be getting a few more TM16's for a few bits - water pump controller, heater controller. Or maybe a <a href="https://www.itead.cc/smart-home/sonoff-pow-r2.html">POW R2</a>, which looks like a slightly cutdown version of the TM16 with a power meter on it.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Wellington to Auckland by Train]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>For my sister-in-laws birthday, we all flew down to Wellington, then caught the train up to Auckland on the <a href="http://railnewzealand.com/train-services/the-northern-explorer">Northern Explorer</a>.</p>
<p><img src="https://fastchicken.co.nz/content/images/2018/06/IMG_1934.JPG" alt="Leaving Wellington"></p>
<p><img src="https://fastchicken.co.nz/content/images/2018/06/IMG_1937-1.JPG" alt="Kapiti Coast"></p>
<p><img src="https://fastchicken.co.nz/content/images/2018/06/IMG_1940.JPG" alt="Rangitikei River"></p>
<p><img src="https://fastchicken.co.nz/content/images/2018/06/IMG_1948.jpg" alt="Mt Ruapehu"></p>
<p><img src="https://fastchicken.co.nz/content/images/2018/06/IMG_1960.jpg" alt="Mt Tongariro and Mt Ngauruhoe"></p>
<p><img src="https://fastchicken.co.nz/content/images/2018/06/IMG_1970.jpg" alt="Sunset in the Waikato"></p>
<!--kg-card-end: markdown-->]]></description><link>https://fastchicken.co.nz/2018/06/23/wellington-to-auckland-by-train/</link><guid isPermaLink="false">5b2ca15ed0bdc42246890b73</guid><dc:creator><![CDATA[Nic Wise]]></dc:creator><pubDate>Sat, 23 Jun 2018 08:31:27 GMT</pubDate><media:content url="https://fastchicken.co.nz/content/images/2018/06/IMG_1948-1.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://fastchicken.co.nz/content/images/2018/06/IMG_1948-1.jpg" alt="Wellington to Auckland by Train"><p>For my sister-in-laws birthday, we all flew down to Wellington, then caught the train up to Auckland on the <a href="http://railnewzealand.com/train-services/the-northern-explorer">Northern Explorer</a>.</p>
<p><img src="https://fastchicken.co.nz/content/images/2018/06/IMG_1934.JPG" alt="Wellington to Auckland by Train"></p>
<p><img src="https://fastchicken.co.nz/content/images/2018/06/IMG_1937-1.JPG" alt="Wellington to Auckland by Train"></p>
<p><img src="https://fastchicken.co.nz/content/images/2018/06/IMG_1940.JPG" alt="Wellington to Auckland by Train"></p>
<p><img src="https://fastchicken.co.nz/content/images/2018/06/IMG_1948.jpg" alt="Wellington to Auckland by Train"></p>
<p><img src="https://fastchicken.co.nz/content/images/2018/06/IMG_1960.jpg" alt="Wellington to Auckland by Train"></p>
<p><img src="https://fastchicken.co.nz/content/images/2018/06/IMG_1970.jpg" alt="Wellington to Auckland by Train"></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Waikaremoana, 2017]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>We go year-about, having one year on the island, and one year doing something else. Last time, <a href="https://fastchicken.co.nz/2016/01/02/routeburn-track-christmas/">we walked the Routeburn Track</a>.</p>
<p>This time it was a return to <a href="https://www.google.co.nz/maps/place/Lake+Waikaremoana/@-38.7606996,177.0361975,13z/data=!3m1!4b1!4m5!3m4!1s0x6d68d0201698c4c9:0x2a00ef6165e1db00!8m2!3d-38.7745378!4d177.1123564">Lake Waikaremoana</a>, in Te Urewera.</p>
<p><img src="https://fastchicken.co.nz/content/images/2017/12/Screen-Shot-2017-12-29-at-18.15.34.png" alt="Screen-Shot-2017-12-29-at-18.15.34"></p>
<p>I've not been there for a few years, but it is, hands down, my favourate place</p>]]></description><link>https://fastchicken.co.nz/2017/12/31/waikaremoana-2017/</link><guid isPermaLink="false">5a45cbff56de1f056f74eccd</guid><dc:creator><![CDATA[Nic Wise]]></dc:creator><pubDate>Sun, 31 Dec 2017 21:12:10 GMT</pubDate><media:content url="https://fastchicken.co.nz/content/images/2017/12/DAY1_1619-1.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://fastchicken.co.nz/content/images/2017/12/DAY1_1619-1.jpg" alt="Waikaremoana, 2017"><p>We go year-about, having one year on the island, and one year doing something else. Last time, <a href="https://fastchicken.co.nz/2016/01/02/routeburn-track-christmas/">we walked the Routeburn Track</a>.</p>
<p>This time it was a return to <a href="https://www.google.co.nz/maps/place/Lake+Waikaremoana/@-38.7606996,177.0361975,13z/data=!3m1!4b1!4m5!3m4!1s0x6d68d0201698c4c9:0x2a00ef6165e1db00!8m2!3d-38.7745378!4d177.1123564">Lake Waikaremoana</a>, in Te Urewera.</p>
<p><img src="https://fastchicken.co.nz/content/images/2017/12/Screen-Shot-2017-12-29-at-18.15.34.png" alt="Waikaremoana, 2017"></p>
<p>I've not been there for a few years, but it is, hands down, my favourate place on the planet<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>.</p>
<p><strong>It just feels like.... home.</strong> It always has. I keep coming back to this place for some reason that I can't quite explain, to walk the track, visit the lakes, or just get away from everything and reset.</p>
<p>I've come here has a child. As an adult trying to escape a job I desperatly needed a break from. On our honeymoon. On a final camper trip before going to the UK. On a &quot;do we want to move back to NZ&quot; trip.</p>
<p>I always keep coming back. I hope I always will.</p>
<p><img src="https://fastchicken.co.nz/content/images/2017/12/DAY2_1626.jpg" alt="Waikaremoana, 2017"></p>
<p>It's my chill out space. My stop and reconnect space. My &quot;remember why the fuck I'm doing all of this&quot; space. It was the part of NZ I missed the most while we were away.</p>
<p>I've walked this track many times. I think I did it first at about 4 years old, and I've done it maybe 5 or 6 times since. Back then it used to cost 50c for kids, and $1 for adults, in the honestly box in each hut. Now it's a &quot;great walk&quot;, $35 for an adult, and don't even start without a booking cos it's booked solid.</p>
<p>I'm ok with that.</p>
<p><img src="https://fastchicken.co.nz/content/images/2017/12/DAY1_1619.jpg" alt="Waikaremoana, 2017"></p>
<p>And I love seeing the diversity of people walking it. Chinese/Asian New Zealanders, Pakeha, European tourists (German, Swiss, American, Canadian), Kiwis - hell, we met 3 groups of people from Waiheke!</p>
<p>This is the first time I've done it this way around (Onepoto -&gt; Hopuruahine<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>). We always did it the other way for some reason, which might have more to do with my parents desire to cut a day off the end than anything.</p>
<p>Except one time, when we got to the top of the bluff to find the water tanks all frozen and we had to turn back. It was no different this time - water was still scarce, but at least it wasn't frozen. It was good and bad to get the bluff done on the first day - good in that it's done, bad in that I have 4 days of food in my pack, not zero.</p>
<p><img src="https://fastchicken.co.nz/content/images/2017/12/DAY1_1620.jpg" alt="Waikaremoana, 2017"></p>
<p>Compared to the walk up the hill, the walk down is an easy 2.5-3 hour jaunt. But throw in some mist (The Tūhoe have the name &quot;children of the mist&quot; for a reason) and it's a stunning morning walk, ending in a swim at the hut.</p>
<p><img src="https://fastchicken.co.nz/content/images/2017/12/DAY2_1624.jpg" alt="Waikaremoana, 2017"></p>
<p>Day 3 starts with a walk to the Korokoro Falls (half an hour from the track, without your pack). It's very worth the walk tho.</p>
<p><img src="https://fastchicken.co.nz/content/images/2017/12/DAY3_1641.jpg" alt="Waikaremoana, 2017"></p>
<p>And finally to the Marauiti Hut, which I swear hasn't changed in 25 years.</p>
<p><img src="https://fastchicken.co.nz/content/images/2017/12/DAY3_1648.jpg" alt="Waikaremoana, 2017"></p>
<p><img src="https://fastchicken.co.nz/content/images/2017/12/DAY3_1649.jpg" alt="Waikaremoana, 2017"></p>
<p><img src="https://fastchicken.co.nz/content/images/2017/12/DAY3_1651.jpg" alt="Waikaremoana, 2017"></p>
<p>The last day is a nice, flat walk to the Whanganui Hut, and the water taxi back to the car.</p>
<p><img src="https://fastchicken.co.nz/content/images/2017/12/DAY4_1652.jpg" alt="Waikaremoana, 2017"></p>
<p><img src="https://fastchicken.co.nz/content/images/2017/12/DAY4_1653.jpg" alt="Waikaremoana, 2017"></p>
<p><img src="https://fastchicken.co.nz/content/images/2017/12/DAY4_1655.jpg" alt="Waikaremoana, 2017"></p>
<p>This hut, Waiharuru, didn't exist when I did it last (around 1992 or so). It was a tiny hut called Te Puna, which was only ever used by &quot;boaties&quot; because of it's location. This is, by far, the fanciest hut on the track.</p>
<p><img src="https://fastchicken.co.nz/content/images/2017/12/DAY4_1660.jpg" alt="Waikaremoana, 2017"></p>
<h2 id="201712_waikaremoanadayfour1"><img src="https://fastchicken.co.nz/content/images/2017/12/201712_Waikaremoana-Dayfour-1.jpg" alt="Waikaremoana, 2017"></h2>
<p><img src="https://fastchicken.co.nz/content/images/2017/12/DAY1_1616.jpg" alt="Waikaremoana, 2017"></p>
<p>Leonie has written some about it, too:</p>
<ul>
<li><a href="https://leoniewise.com/lake-waikaremoana-track-day-one/">Waikaremoana Day 1</a></li>
<li><a href="https://leoniewise.com/lake-waikaremoana-track-day-two/">Waikaremoana Day 2</a></li>
<li><a href="https://leoniewise.com/lake-waikaremoana-track-day-three/">Waikaremoana Day 3</a></li>
<li><a href="https://leoniewise.com/lake-waikaremoana-track-day-four/">Waikaremoana Day 4</a></li>
</ul>
<hr>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>Maybe there is some <a href="https://en.wikipedia.org/wiki/Ng%C4%81i_T%C5%ABhoe">Tūhoe</a> in my (distant, spiritual) past somewhere. Based on the few I've met, I'd consider that an honor. <a href="#fnref1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p>pronounced: Hope-rah-heee-nay, tho the first H is quite light/silent <a href="#fnref2" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Apple Watch 2 - 12 months later]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>So last year, when Apple re-released the Apple Watch as <a href="https://www.apple.com/apple-watch-series-2/">Apple Watch Series 2</a>, I decided to get one again.</p>
<p>Yes, again.</p>
<p>I got the developer-release Series 0 special version thing they did the year before, because why not, they discounted it pretty heavily<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>.</p>
<p>That time around, I got</p>]]></description><link>https://fastchicken.co.nz/2017/09/02/apple-watch-2-12-months-later/</link><guid isPermaLink="false">59aa00080f8655412d6b4557</guid><dc:creator><![CDATA[Nic Wise]]></dc:creator><pubDate>Sat, 02 Sep 2017 01:12:42 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>So last year, when Apple re-released the Apple Watch as <a href="https://www.apple.com/apple-watch-series-2/">Apple Watch Series 2</a>, I decided to get one again.</p>
<p>Yes, again.</p>
<p>I got the developer-release Series 0 special version thing they did the year before, because why not, they discounted it pretty heavily<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>.</p>
<p>That time around, I got the 42mm one. It was ok - but not great. The software was laggy and unpolished, but mostly, the size was too big. I have fairly big wrists, but I prefer a minimum of things on my hands - I don't wear my wedding band, or anything else, for example<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>.</p>
<p>So the 42mm Series 0 lasted about a month.</p>
<p>However, work-at-the-time also got a 38mm for testing, and as we were not using it all the time for dev work, I tried that out a bit, and it worked a lot better - the smaller size was great.</p>
<p>So I waited for the Series 2 (GPS is a big plus with cycling) and got a 38mm Space Grey Series 2. (I was going to wait for the Nike+ one, but I decided not to - I just wanted the band, which they sell separately now anyway!)</p>
<p><img src="https://fastchicken.co.nz/content/images/2017/09/apple-watch.jpg" alt="apple-watch"></p>
<p>To my surprise, I'm still wearing it and using it, nearly 12 months later.</p>
<p>So what do I use it for? The main use is still exercise and heart monitoring. I use <a href="http://heartwatch.tantsissa.com/">Heartwatch</a> on my phone to keep an eye on my heart rate, and the built in exercise app if I'm at the gym or going for a ride. I sometimes also use the native <a href="https://www.strava.com/">Strava</a> app at the same time, as you can't <em>yet</em> export from the built in Exercise app to a 3rd party (I think iOS 11 fixes this).</p>
<p>But the 2 surprise apps I use the most are for work: <a href="https://itunes.apple.com/nz/app/pagerduty/id594039512?mt=8">PagerDuty</a> and <a href="https://itunes.apple.com/us/app/duo-mobile/id422663827?mt=8">Duo</a>. If I'm logging into our VPN, I get a Duo 2FA push, which I can accept on the watch, and if I get paged, the watch vibrates, and I can ACK it from there. I normally have PD only phone me if I've not responded for 60 seconds.</p>
<p>It sounds minor, but it's become a core part of my workflow. I could do without these, but being I have the watch already, they are super useful.</p>
<p>Being able to log into my (work) computer without using the password is great, too - it also means I can have a much longer and more complex password on my Mac. It's just a pity a few other parts of macOS do not support it (eg dialogs, <code>sudo</code> and the like).</p>
<p>So much to my surprise, I'm still using and wearing it. I've turned off most of the notifications, so it's not fairly quiet, tho I have a few I need to turn off around exercise goals (I don't need to know, mid-workout, that I've just completed the exercise rings). I have watchOS 4 beta on it at present, and while it's not a big jump, they have made it that bit nicer again - the workouts app got a revamp, as did the general flow of stuff. It's feeling very polished now.</p>
<p>The rumor mill is saying that the next one will have a cell connection on it, but I'm not convinced - or rather, I'm not convinced I'd want it if they did. We'll see tho - it's a big component in terms of chip space and battery use, so if Apple does it, they'll have an excellent reason for it.</p>
<p>Bring on Sept 12th!</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>I ended up selling it to work (ANZ). <a href="#fnref1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p>Long story around that one :) Ask me sometime over a beer. <a href="#fnref2" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>