added QE feedback

added QE feedback

// Module included in the following assemblies:
//
// * serverless/release-notes.adoc

[id="serverless-rn-1-12-0_{context}"]

= Release Notes for Red Hat {ServerlessProductName} 1.12.0

[id="new-features-1-12-0_{context}"]
== New features

* {ServerlessProductName} now uses Knative Serving 0.18.2.
* {ServerlessProductName} uses Knative Eventing 0.18.6.
* {ServerlessProductName} now uses Kourier 0.18.0.
* {ServerlessProductName} now uses Knative `kn` CLI 0.18.4.
* {ServerlessProductName} now uses Knative Kafka 0.18.0.

[id="fixed-issues-1-12-0_{context}"]
== Fixed issues

* In previous versions, if you used a ping source with OpenShift Serverless, after you uninstalled and deleted all other Knative Eventing components, the `pingsource-jobrunner` deployment was not deleted. This issue is now fixed, and the `pingsource-jobrunner` deployment has been renamed to `pingsource-mt-adapter`.
* In previous versions, deleting a sink before you delete the `SinkBinding` resource connected to it caused the resource deletion to hang. This issue is now fixed.

[id="known-issues-1-12-0_{context}"]
== Known issues

* Using the `eventing.knative.dev/scope: namespace` annotation for the `KafkaChannel` objects is not supported.

// Module included in the following assemblies:
//
// * serverless/release-notes.adoc

[id="serverless-rn-1-12-0_{context}"]

= Release Notes for Red Hat {ServerlessProductName} 1.12.0

[id="new-features-1-12-0_{context}"]
== New features

* {ServerlessProductName} now uses Knative Serving 0.18.2.
* {ServerlessProductName} uses Knative Eventing 0.18.6.
* {ServerlessProductName} now uses Kourier 0.18.0.
* {ServerlessProductName} now uses Knative `kn` CLI 0.18.4.
* {ServerlessProductName} now uses Knative Kafka 0.18.0.

[id="fixed-issues-1-12-0_{context}"]
== Fixed issues

[id="known-issues-1-12-0_{context}"]
== Known issues

* Using the `eventing.knative.dev/scope: namespace` annotation for the `KafkaChannel` objects is not supported.


clarify Tag Inclusions/Exclusion

clarify Tag Inclusions/Exclusion

:icons: font
:imagesdir: C:\_My Documents\FlowWritingLLC\Projects\Kill Bill\Documentation\killbill-docs\userguide\assets\img\kaui

=== Overview

Kaui lets you configure basic settings for how the system behaves when an account is overdue. For overdue configuration, you define:

* The various states that the account must go through
* The change in users' entitlements when the account is transitioned from one state to the other
* The period after which the state is re-evaluated

These three pieces of information make up the _overdue flow_.

Overdue configuration applies at the tenant level. However you can also configure overdue flows for the _global_ Kill Bill system.

In Kaui, overdue configuration is a subset of the full overdue configuration settings. For more information on the full configuration settings and global settings, see the https://docs.killbill.io/latest/overdue.html[_Overdue System Guide_].

See the following sections to create overdue (dunning) flows for a tenant:

[cols="1,1"]
[frame=none]
[grid=none]
|===

a| * <<View Overdue Configuration,View overdue configuration>>
* <<Create Overdue Flows,Create overdue flows>>
* <<Upload an XML Overdue Configuration File,Upload an XML overdue configuration file>>

a| * <<View Overdue Configuration as XML,View overdue configuration as XML>>
* <<Delete Overdue Flows,Delete overdue flows>>

|===

==== Additional Overdue Resources

* https://docs.killbill.io/latest/userguide_subscription.html#components-overdue["Overdue"] section in the _Subscription Guide_.
* https://docs.killbill.io/latest/overdue.html[_Overdue System Guide_]

=== View Overdue Configuration

If any overdue (dunning) flows are configured, you can see them on the Overdue Show tab at the bottom of the Tenant Configuration page. To get there:

. Click on your username and tenant name in the upper right corner:
+
image::Users-SelectTenantName.png[width=650,align="center"]
+
Kaui displays the Tenant Configuration page.
+
. Scroll down and click on the Overdue Show tab:
+
image::OverdueTab.png[width=850,align="center"]

=== Create Overdue Flows

The following steps explain how to set up overdue flows (i.e., actions) for the tenant.

. <<View Overdue Configuration,Go to the Overdue Show tab>> on the Tenant Configuration page.
+
image::OverdueTab.png[width=850,align="center"]
+
. Click the plus sign ( image:i_PlusGreen.png[] ) next to *Existing Overdue Config*.
+
Kaui opens the Overdue Configuration screen:
+
image::OverdueConfig-Empty.png[width=850,align="center"]
+
. Click *+ New Overdue States*. Kaui opens the fields for editing:
+
image::OverdueConfig-BlankFields.png[width=850,align="center"]
+
. Fill in the fields for the current row. For field information, see the <<Overdue Configuration Field Descriptions>> table.
+
. To add another overdue configuration row, click *+ new overdue states*.
+
image::Overdue-Select-NewOverdueState.png[width=450,align="center"]
+
. When you are done adding configuration rows, click the *Save* button. Kaui displays a success message at the top of the screen and displays the new overdue flow(s) on the Overdue Show tab.
+
image::Overdue-ShowFlows.png[width=850,align="center"]

[NOTE]
*Note:* To edit an existing overdue flow, on the Overdue Show tab, click the plus sign ( image:i_PlusGreen.png[] ) next to *Existing Overdue Config*. This opens the overdue configuration fields in edit mode.

=== Overdue Configuration Field Descriptions

[cols="1,3"]
|===
^|Field ^|Description

| Name
| The name assigned to the overdue state.

| External Message
| Message text that other plugins, when listening for overdue events, can retrieve and display to the user. (_Optional_)

| Block Subscription Changes
| If set to `true`, the customer _cannot_ make plan changes to the subscription in this overdue flow. If set to `false`, the customer is allowed to make changes.

| Subscription Cancellation
a| Select the option that describes how Kill Bill behaves regarding a cancellation in this overdue flow:

* `NONE`: Kill Bill ignores this field, and the subscription is not cancelled.

* `POLICY_NONE`: ??? _Maybe some to do with the default cancellation policy in the catalog? Not sure..._

* `POLICY_IMMEDIATE_POLICY`: Cancels the subscription immediately and applies a partial credit to the
account based on how much of the service has been consumed.

* `POLICY_END_OF_TERM`: Cancels the subscription at the end of the billing period with no refund to
the customer (i.e., no proration).

| Days Since Earliest Unpaid Invoice
| Specifies how many days should pass after the last unpaid invoice before initiating this overdue flow.

| Tag Inclusion
a| Specifies that the overdue flow will occur if the account has a system (control) tag matching the one selected here. To disregard tag inclusion for this overdue flow, leave as the default `NONE` setting.

* `AUTO_PAY_OFF`
* `AUTO_INVOICING_OFF`
* `OVERDUE_ENFORCEMENT_OFF`
* `MANUAL_PAY`
* `TEST`
* `PARTNER`

For a description of system tags, see the https://docs.killbill.io/latest/userguide_subscription.html#components-tag["Tags"] section of the _Subscription Guide_.

| Tag Exclusion
| Specifies that overdue flow will occur if the account has NO system (control) tags matching the one selected here. To disregard tag exclusion for this overdue flow, leave as the default `NONE` setting.

| Number of Unpaid Invoices
| Specifies that the overdue flow will occur if the number of unpaid invoices equals or exceeds the specified value.

| Total Unpaid Invoice Balance
| Specifies that the overdue action will occur if the total unpaid invoice balance equals or exceeds the specified value.

|===

=== Upload an XML Overdue Configuration File

Kill Bill overdue configuration is stored in XML format. This section explains how to upload an XML file that contains the overdue configuration.

[NOTE]
*Note*: You cannot edit a raw overdue configuration XML file in Kaui.

. <<View Overdue Configuration,Go to the Overdue Show tab>> on the Tenant Configuration page.
+
image::OverdueTab.png[width=850,align="center"]
+
. Click the plus sign ( image:i_PlusGreen.png[] ) next to *Existing Overdue Config*.
+
Kaui opens the Overdue Configuration screen:
+
image::OverdueConfig-Empty.png[width=850,align="center"]
+
. Click *Enable Advanced Configuration (Upload XML)*. Kaui displays an upload screen:
+
image::Overdue-AdvancedConfigUpload.png[width=450,align="center"]
+
. Click the *Choose File* button, locate the XML file, and select it.
+
Once you have selected the file, Kaui displays the filename next to the *Choose File* button.
+
image::Overdue-AdvancedConfigUpload-File.png[width=450,align="center"]
+
. Click the *Upload* button.
+
If the upload is successful, Kaui displays a success message at the top of the screen and displays the overdue flow(s) on the Overdue Show tab.
+
image::Overdue-ShowUpload.png[width=850,align="center"]

=== View Overdue Configuration as XML

. <<View Overdue Configuration,Go to the Overdue Show tab>> on the Tenant Configuration page.
+
image::OverdueTab.png[width=850,align="center"]
+
. Click *View Overdue XML* to the right of the plus sign ( image:i_PlusGreen.png[] ). Kaui displays the raw XML (uneditable in this view).
+
. To return to Kaui, click the Back arrow button of your browser.

=== Delete Overdue Flows

. <<View Overdue Configuration,Go to the Overdue Show tab>> on the Tenant Configuration page.
+
image::OverdueTab.png[width=850,align="center"]
+
. Click the plus sign ( image:i_PlusGreen.png[] ) next to *Existing Overdue Config*.
+
Kaui opens the Overdue Configuration screen.
+
. Click the red X ( image:i_RedX.png[] ) to the right of every configuration row you want to delete.
+
image::Overdue-Select-Delete.png[width=850,align="center"]
+
. Click the *Save* button.
+
Kaui removes the overdue configuration row(s) from the Overdue Show tab and displays a delete confirmation message.

:icons: font
:imagesdir: C:\_My Documents\FlowWritingLLC\Projects\Kill Bill\Documentation\killbill-docs\userguide\assets\img\kaui

=== Overview

Kaui lets you configure basic settings for how the system behaves when an account is overdue. For overdue configuration, you define:

* The various states that the account must go through
* The change in users' entitlements when the account is transitioned from one state to the other
* The period after which the state is re-evaluated

These three pieces of information make up the _overdue flow_.

Overdue configuration applies at the tenant level. However you can also configure overdue flows for the _global_ Kill Bill system.

In Kaui, overdue configuration is a subset of the full overdue configuration settings. For more information on the full configuration settings and global settings, see the https://docs.killbill.io/latest/overdue.html[_Overdue System Guide_].

See the following sections to create overdue (dunning) flows for a tenant:

[cols="1,1"]
[frame=none]
[grid=none]
|===

a| * <<View Overdue Configuration,View overdue configuration>>
* <<Create Overdue Flows,Create overdue flows>>
* <<Upload an XML Overdue Configuration File,Upload an XML overdue configuration file>>

a| * <<View Overdue Configuration as XML,View overdue configuration as XML>>
* <<Delete Overdue Flows,Delete overdue flows>>

|===

==== Additional Overdue Resources

* https://docs.killbill.io/latest/userguide_subscription.html#components-overdue["Overdue"] section in the _Subscription Guide_.
* https://docs.killbill.io/latest/overdue.html[_Overdue System Guide_]

=== View Overdue Configuration

If any overdue (dunning) flows are configured, you can see them on the Overdue Show tab at the bottom of the Tenant Configuration page. To get there:

. Click on your username and tenant name in the upper right corner:
+
image::Users-SelectTenantName.png[width=650,align="center"]
+
Kaui displays the Tenant Configuration page.
+
. Scroll down and click on the Overdue Show tab:
+
image::OverdueTab.png[width=850,align="center"]

=== Create Overdue Flows

The following steps explain how to set up overdue flows (i.e., actions) for the tenant.

. <<View Overdue Configuration,Go to the Overdue Show tab>> on the Tenant Configuration page.
+
image::OverdueTab.png[width=850,align="center"]
+
. Click the plus sign ( image:i_PlusGreen.png[] ) next to *Existing Overdue Config*.
+
Kaui opens the Overdue Configuration screen:
+
image::OverdueConfig-Empty.png[width=850,align="center"]
+
. Click *+ New Overdue States*. Kaui opens the fields for editing:
+
image::OverdueConfig-BlankFields.png[width=850,align="center"]
+
. Fill in the fields for the current row. For field information, see the <<Overdue Configuration Field Descriptions>> table.
+
. To add another overdue configuration row, click *+ new overdue states*.
+
image::Overdue-Select-NewOverdueState.png[width=450,align="center"]
+
. When you are done adding configuration rows, click the *Save* button. Kaui displays a success message at the top of the screen and displays the new overdue flow(s) on the Overdue Show tab.
+
image::Overdue-ShowFlows.png[width=850,align="center"]

[NOTE]
*Note:* To edit an existing overdue flow, on the Overdue Show tab, click the plus sign ( image:i_PlusGreen.png[] ) next to *Existing Overdue Config*. This opens the overdue configuration fields in edit mode.

=== Overdue Configuration Field Descriptions

[cols="1,3"]
|===
^|Field ^|Description

| Name
| The name assigned to the overdue state.

| External Message
| Message text that other plugins, when listening for overdue events, can retrieve and display to the user. (_Optional_)

| Block Subscription Changes
| If set to `true`, the customer _cannot_ make plan changes to the subscription in this overdue flow. If set to `false`, the customer is allowed to make changes.

| Subscription Cancellation
a| Select the option that describes how Kill Bill behaves regarding a cancellation in this overdue flow:

* `NONE`: The subscription is not cancelled.

* `POLICY_NONE`: ??? _Maybe some to do with the default cancellation policy in the catalog? Not sure..._

* `POLICY_IMMEDIATE_POLICY`: Cancels the subscription immediately and applies a partial credit to the
account based on how much of the service has been consumed.

* `END_OF_TERM`: Cancels the subscription at the end of the billing period with no refund to
the customer (i.e., no proration).

| Days Since Earliest Unpaid Invoice
| Specifies how many days should pass after the last unpaid invoice before initiating this overdue flow.

| Tag Inclusion
a| Specifies that the overdue flow will occur if the account is tagged with one of the selected system (control) tags. To disregard tag inclusion for this overdue flow, leave as the default `NONE` setting.

* `AUTO_PAY_OFF`
* `AUTO_INVOICING_OFF`
* `OVERDUE_ENFORCEMENT_OFF`
* `MANUAL_PAY`
* `TEST`
* `PARTNER`

For a description of system tags, see the https://docs.killbill.io/latest/userguide_subscription.html#components-tag["Tags"] section of the _Subscription Guide_.

| Tag Exclusion
| Specifies that the overdue flow will occur if the account is _not_ tagged with one of the selected system (control) tags. (See tags information above.) To disregard tag exclusion for this overdue flow, leave as the default `NONE` setting.

| Number of Unpaid Invoices
| Specifies that the overdue flow will occur if the number of unpaid invoices equals or exceeds the specified value.

| Total Unpaid Invoice Balance
| Specifies that the overdue action will occur if the total unpaid invoice balance equals or exceeds the specified value.

|===

=== Upload an XML Overdue Configuration File

Kill Bill overdue configuration is stored in XML format. This section explains how to upload an XML file that contains the overdue configuration.

[NOTE]
*Note*: You cannot edit a raw overdue configuration XML file in Kaui.

. <<View Overdue Configuration,Go to the Overdue Show tab>> on the Tenant Configuration page.
+
image::OverdueTab.png[width=850,align="center"]
+
. Click the plus sign ( image:i_PlusGreen.png[] ) next to *Existing Overdue Config*.
+
Kaui opens the Overdue Configuration screen:
+
image::OverdueConfig-Empty.png[width=850,align="center"]
+
. Click *Enable Advanced Configuration (Upload XML)*. Kaui displays an upload screen:
+
image::Overdue-AdvancedConfigUpload.png[width=450,align="center"]
+
. Click the *Choose File* button, locate the XML file, and select it.
+
Once you have selected the file, Kaui displays the filename next to the *Choose File* button.
+
image::Overdue-AdvancedConfigUpload-File.png[width=450,align="center"]
+
. Click the *Upload* button.
+
If the upload is successful, Kaui displays a success message at the top of the screen and displays the overdue flow(s) on the Overdue Show tab.
+
image::Overdue-ShowUpload.png[width=850,align="center"]

=== View Overdue Configuration as XML

. <<View Overdue Configuration,Go to the Overdue Show tab>> on the Tenant Configuration page.
+
image::OverdueTab.png[width=850,align="center"]
+
. Click *View Overdue XML* to the right of the plus sign ( image:i_PlusGreen.png[] ). Kaui displays the raw XML (uneditable in this view).
+
. To return to Kaui, click the Back arrow button of your browser.

=== Delete Overdue Flows

. <<View Overdue Configuration,Go to the Overdue Show tab>> on the Tenant Configuration page.
+
image::OverdueTab.png[width=850,align="center"]
+
. Click the plus sign ( image:i_PlusGreen.png[] ) next to *Existing Overdue Config*.
+
Kaui opens the Overdue Configuration screen.
+
. Click the red X ( image:i_RedX.png[] ) to the right of every configuration row you want to delete.
+
image::Overdue-Select-Delete.png[width=850,align="center"]
+
. Click the *Save* button.
+
Kaui removes the overdue configuration row(s) from the Overdue Show tab and displays a delete confirmation message.


Update 2016-04-06-Early-Breakfast-in-Fantasyland.adoc

= Early Breakfast in Fantasyland
:hp-tags: Disney World, Magic Kingdom, News

image::covers/7DMT_Doc.jpg[caption="Doc in the Seven Dwarfs Mine Train"]

One of the biggest decisions you'll make when planning a Disney World vacation is whether to eat a good breakfast before going to the parks or going straight to the parks to be the first in line for some of your favorite attractions. Now you can choose both if you take advantage of "Disney Early Morning Magic".

On select mornings from 7:45-10:00am, a very limited number of guests will be the first to enter the Magic Kingdom and Fantasyland. At _Pinocchio Village Haus_, you can enjoy a breakfast that includes pastries, fruits, scrambled eggs, waffles, bacon, sausage, and much more. And before the crowds get too heavy, you'll have quick access to _Peter Pan's Flight_, _Seven Dwarfs Mine Train_, and _The Many Adventures of Winnie the Pooh_.

This special early morning access to Fantasyland will cost $69 for adults and $59 for children (ages 3-9) in addition to regular park admission. It appears that it will be offered on most Tuesday and Saturday mornings starting April 26th. If this is something you think you might want to try out, you can read more about it and check for availability by clicking https://disneyworld.disney.go.com/dining/early-morning-magic[here].

It's important to understand that although this event runs from 7:45-10:00am, the Magic Kingdom still opens at 9:00am on those days. So participating guests will only have exclusive access to Fantasyland for an hour and 15 minutes (unless they plan to keep Fantasyland closed to regular guests until 10:00am--which is unlikely). Therefore, we're undecided if breakfast plus quick access to those three rides in such a short period of time justifies the $69/person price tag. In comparison, breakfast at _Cinderella's Royal Table_ is roughly $60 for adults and $36 for children, which includes the experience of dining in the castle, albeit without quick access to 3 Fantasyland attractions.

What do you think? Does "Disney Early Morning Magic" seem like something you'd want to try? Leave us a comment and let us know.

= Breakfast in Fantasyland
:hp-tags: Disney World, Magic Kingdom, News

image::covers/7DMT_Doc.jpg[caption="Doc in the Seven Dwarfs Mine Train"]

One of the biggest decisions you'll make when planning a Disney World vacation is whether to eat a good breakfast before going to the parks or going straight to the parks to be the first in line for some of your favorite attractions. Now you can choose both if you take advantage of "Disney Early Morning Magic".

On select mornings from 7:45-10:00am, a very limited number of guests will be the first to enter the Magic Kingdom and Fantasyland. At _Pinocchio Village Haus_, you can enjoy a breakfast that includes pastries, fruits, scrambled eggs, waffles, bacon, sausage, and much more. And before the crowds get too heavy, you'll have quick access to _Peter Pan's Flight_, _Seven Dwarfs Mine Train_, and _The Many Adventures of Winnie the Pooh_.

This special early morning access to Fantasyland will cost $69 for adults and $59 for children (ages 3-9) in addition to regular park admission. It appears that it will be offered on most Tuesday and Saturday mornings starting April 26th. If this is something you think you might want to try out, you can read more about it and check for availability by clicking https://disneyworld.disney.go.com/dining/early-morning-magic[here].

It's important to understand that although this event runs from 7:45-10:00am, the Magic Kingdom still opens at 9:00am on those days. So participating guests will only have exclusive access to Fantasyland for an hour and 15 minutes (unless they plan to keep Fantasyland closed to regular guests until 10:00am--which is unlikely). Therefore, we're undecided if breakfast plus quick access to those three rides in such a short period of time justifies the $69/person price tag. In comparison, breakfast at _Cinderella's Royal Table_ is roughly $60 for adults and $36 for children, which includes the experience of dining in the castle, albeit without quick access to 3 Fantasyland attractions.

What do you think? Does "Disney Early Morning Magic" seem like something you'd want to try? Leave us a comment and let us know.


Update 2016-05-20-Assumptions-driven-development.adoc

= Assumptions driven-development
:hp-image: /covers/assumptions-driven-development.jpeg
:hp-tags: learning, development
:hp-alt-title: Assumptions driven-development
:published_at: 2016-05-20
:my-twitter-link: https://twitter.com/mikealdo007[@mikealdo007]
:yegor-debugging-link: http://www.yegor256.com/2016/02/09/are-you-still-debugging.html[Yegor]
:pomodoro-link: https://mikealdo.github.io/2016/03/14/Pomodoro-and-happiness-in-developer-life.html[Pomodoro's]
:self-retro-link: https://mikealdo.github.io/2016/03/18/Self-retrospective-increases-happiness-of-life.html[self-retrospective]
:cover-link: https://unsplash.com/photos/ZSvlTa6yARw[Tomas Salas | unsplash.com]

It’s quite hard to admit, but recently I have almost entirely failed with initial design and implementation of one of the features needed in software on which I am currently working. It’s even more challenging when I have a meaning about myself as pretty established, experienced developer. This "almost fail" leads to me to the fact, that there is always something new to learn and there is still need to open question even for the easiest problems.

== Assumptions are bad
All this story and throwing away my two-week work (almost all) started with the lack of communication and vague description of the task. Even when I have opened some questions, they were answered a little bit vaguely and without the thorough understanding of respondent. Also, documentation was very broad and almost only about the product itself, not so many technical details about affected area. And documentation inside codebase? Just hard to use or undocumented code. So I started to think about “how this and this part of software works” on my own by looking at documentation and to the code, test codebase and (of course) debugging. By the way, I agree with {yegor-debugging-link}, if you are debugging something, it is a sign that is something wrong.

== Fail trajectory
I have collected all errors bellow:

* *Fail 1:* As the codebase were pretty large I have created own assumptions, own mind maps about the parts of the architecture.
** Then I was trying to invent solution passing to *my* understandings of code. Ultimately wrong.
* *Fail 2:* I was presuming that is expected to understand all the code with the only slight help of others as others seemed to be very busy.
** And probably as my ego was big enough for fighting the task alone.
* *Fail 3:* I was too early convinced that I can come with the reasonable solution and immediately start working on the proof of concept (POC).
* *Fail 4:* After I designed the POC and proven that might work I was not diligent enough to discuss my solution with a broad audience if the solution fits the architecture, further development or future features.
* *Fail 5:* As my POC confirmed that it can work I started working on implementation details in one part of the application before scanning all of the affected areas.
** And not surprisingly in two code areas, it was very hard and wrong by my design to incorporate my design into these parts of the codebase.
* *Fail 6:* After some pressure had come, I avoided working in {pomodoro-link} style to achieve “better” productivity and after a whole day of developing I was just so overwhelmed.
** The big picture immediately went away. Productivity was even worse. My personal feeling was bad as well. One positive point is that I realized that it’s not working quite early and returned to Pomodoro's after one and half day. At least something.
* *Fail 7:* I didn’t make an analysis of all technologies used in the project and how can be replaced or utilized better.
* *Fail 8:* Code review was not done periodically on small amount of code but on the code produced after two-weeks development.

== How it ended?
On the end, it was a success. But more than three weeks work in addition to two weeks spent on the wrong implementation. Beginning of the success started mainly due to my personal {self-retro-link} by my opinion. I am doing it for more than for months and after the second week and revisiting all the work done, I realized that I wasn't able to deliver something feasible in two weeks, and it's just wrong. Then I was communicating with others more thorougly; I was organizing sessions with opened development environment, and I was deeply analyzing all the suggestions. I returned to the implementation after three days of communication, meetings and with clear steps defined to achieve the goal of my task.

== Suggestion for all developers
If you are self-reflexive enough, you can reckognize one of the fail above. The point is to realize this fail fast to avoid unnecessary work, throwned code, and frustration. You are not alone and not working alone, there is always someone to ask, to discuss possible solutions deeply and getting rid of fails mentioned above. Be more experienced and mature developer!

*P.S.* If you enjoyed this post, you can follow me on {my-twitter-link} to stay in touch with my articles and other thoughts.

*P.S.2* Cover image by {cover-link}.


Update 2017-05-13-DNS-Whitelist-in-BIND-with-RPZ.adoc

= DNS Whitelist in BIND with RPZ
 :hp-tags: DNS, Filtering, Firewall, Security

Restricting DNS queries to a specific list of domains.

I recently got a Samsung 'smart' TV which is very nice to look at.

Unfortunately there have been numerous security and privacy issues with smart TVs of all kinds, and Samsung in http://www.bbc.com/news/technology-31296188[particular].  So being predictably paranoid I immediately blocked the TV's IP address on my router to stop it getting to the internet.

As it turns out however, the built-in Netflix app on the TV is my only option for 4k Netflix (my HTPC was out due to not having a Kaby Lake chip).

So I found myself in a situation where I needed to allow the TV get out to the internet, despite my misgivings.

But this got me thinking - could I somehow limit it's access to just Netflix?  I initally tried an IP-based ACL on the router, but there were some issues with that so I began to wonder was there a DNS-based approach I could take?

=== Enter DNS RPZ

I am relatively familiar with https://www.isc.org/downloads/bind[ISC Bind] having used it down through the years, and one feature in particular suggested it might help - Response Policy Zones.

Basically RPZ can be used to create a DNS "firewall," limiting what domains can be resolved.  There is plenty of information online about how this can be set up, however I didn't find anything specifically explaining how to do what I needed (a total blacklist with only a very small whitelist of domains).

Turns out it's fairly easy to do.

=== Bind Configuration

The first step is to get a basic Bind resolver up and running.  I did this with a Ubuntu 16.04 system.

I then configured a 'response-policy' block in the 'options' section of my named.conf (on my particular system I did it in /etc/bind/named.conf.options).  This lists two RPZ zones which are used to define what queries to filter.  The key thing here is that RPZ checks zones in the order they are listed - this is key to creating a whitelist as opposed to a blacklist.  A single line is required:

 response-policy { zone "rpz.whitelist"; zone "rpz"; };

All queries will then be filtered based on the response policy zones listed.  If a match is found in the first (rpz.whitelist) then that will be used, otherwise the second one (rpz) will be checked.

The Bind server needs to be configured as authorititive master for these zones, similar to a standard zone, although with "allow-query" set to none.  Again this is in named.conf (in my case /etc/bind/named.conf.default-zones):

 zone "rpz.whitelist" {
    type master;
    file "/etc/bind/db.rpz.whitelist";
    allow-query { none; };
 };

 zone "rpz" {
    type master;
    file "/etc/bind/db.rpz";
    allow-query { none; };
 };

As can be seen the zone definitions reference the location of the zone files for each.  The files are created as follows, using the RPZ syntax.  The first zone, rpz.whitelist, is where to define the domains we want to allow.  In my case it looks like this:

_/etc/bind/db.rpz.whitelist_:
....
$TTL 60
@            IN    SOA  localhost. root.localhost.  (
                      4   ; serial
                      3H  ; refresh
                      1H  ; retry
                      1W  ; expiry
                      1H) ; minimum

                      IN     NS      localhost.

 netflix.com                 CNAME   rpz-passthru.
 *.netflix.com               CNAME   rpz-passthru.

 nflximg.com                 CNAME   rpz-passthru.
 *.nflximg.com               CNAME   rpz-passthru.

 nflximg.net                 CNAME   rpz-passthru.
 *.nflximg.net               CNAME   rpz-passthru.
....

Note that for each domain I have included the 'apex' record, and also a wildcard to catch all sub-domains.  In each case they are listed as CNAME records pointing to rpz-passthru, which is the RPZ syntax to tell Bind to allow queries for them.

The second RPZ zone file is created as follows.  This is configured for all sub-domains of the root zone, with a CNAME pointing to "." (which tells RPZ to return NXDOMAIN for such a lookup).  As the trailing dot (root zone) is left out of entries in RPZ zones, an asterix on it's own is all that is needed to represent subdomains of the DNS root:

_/etc/bind/db.rpz_:
....
$TTL 60
@            IN    SOA  localhost. root.localhost.  (
                     4   ; serial
                     3H  ; refresh
                     1H  ; retry
                     1W  ; expiry
                     1H) ; minimum

             IN      NS    localhost.

*                    CNAME .
....

With the config in place I was able to reload Bind and check if it was working.

=== Results

So does it work.  If I try to resolve a random domain I get an NXDOMAIN response:

....
topranks@dnsvm:~$ dig A www.samsung.com @localhost

; <<>> DiG 9.10.3-P4-Ubuntu <<>> A www.samsung.com @localhost
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 14003
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 2

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.samsung.com.		IN	A
....

But if I try for a sub-domain of netflix.com I get a valid response:

....
topranks@dnsvm:~$ dig A www.netflix.com @localhost

; <<>> DiG 9.10.3-P4-Ubuntu <<>> A www.netflix.com @localhost
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59390
;; flags: qr rd ra; QUERY: 1, ANSWER: 10, AUTHORITY: 4, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.netflix.com.		IN	A

;; ANSWER SECTION:
www.netflix.com.	1800	IN	CNAME	www.geo.netflix.com.
www.geo.netflix.com.	1800	IN	CNAME	www.eu-west-1.prodaa.netflix.com.
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.209.165.126
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.19.164.15
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.208.178.51
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.209.156.83
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.208.202.184
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.208.15.72
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.208.81.52
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.208.174.58
....

=== Additions for my Smart TV case

In addition to the above I changed the ACL on for traffic coming from the TV to only allow TCP on ports 80 and 443.  This is enough for Netflix, but importantly blocks the TV from using any external DNS (even in normal circumstances it looks like it uses 8.8.8.8 in addition to any DNS server you give it yourself.)

Finally on the TV I changed the DNS server and sure enough the TV thinks something is wrong with DNS:

image::https://cloud.githubusercontent.com/assets/4465905/26027929/bd59e8b2-380e-11e7-81b1-b8b2b8fd2ffe.JPG[Samsung Error Message]

So far so good, and yes the Netflix app still works fine.  Looking closely at my Bind logs I can see what's happening:

....
Apr 20 17:42:27 dnsvm named[7369]: 13-May-2017 17:42:27.003 queries: info: client 192.168.240.42#40665 (art-0.nflximg.net): query: art-0.nflximg.net IN A + (192.168.240.32)
Apr 20 17:42:27 dnsvm named[7369]: 13-May-2017 17:42:27.003 rpz: info: client 192.168.240.42#40665 (art-0.nflximg.net): rpz QNAME PASSTHRU rewrite art-0.nflximg.net via art-0.nflximg.net.rpz.netflix
Apr 20 17:42:27 dnsvm named[7369]: 13-May-2017 17:42:27.766 queries: info: client 192.168.240.42#34179 (ns11.whois.co.kr): query: ns11.whois.co.kr IN A + (192.168.240.32)
Apr 20 17:42:27 dnsvm named[7369]: 13-May-2017 17:42:27.766 rpz: info: client 192.168.240.42#34179 (ns11.whois.co.kr): rpz QNAME NXDOMAIN rewrite ns11.whois.co.kr via ns11.whois.co.kr.rpz
Apr 20 17:42:29 dnsvm named[7369]: 13-May-2017 17:42:29.031 queries: info: client 192.168.240.42#59989 (time.samsungcloudsolution.com): query: time.samsungcloudsolution.com IN A + (192.168.240.32)
Apr 20 17:42:29 dnsvm named[7369]: 13-May-2017 17:42:29.031 rpz: info: client 192.168.240.42#59989 (time.samsungcloudsolution.com): rpz QNAME NXDOMAIN rewrite time.samsungcloudsolution.com via time.samsungcloudsolution.com.rpz
Apr 20 17:42:29 dnsvm named[7369]: 13-May-2017 17:42:29.033 queries: info: client 192.168.240.42#36357 (time.samsungcloudsolution.com): query: time.samsungcloudsolution.com IN A + (192.168.240.32)
Apr 20 17:42:29 dnsvm named[7369]: 13-May-2017 17:42:29.033 rpz: info: client 192.168.240.42#36357 (time.samsungcloudsolution.com): rpz QNAME NXDOMAIN rewrite time.samsungcloudsolution.com via time.samsungcloudsolution.com.rpz
....

So yeah, probably not ideal as the TV can still get out to the internet, at least on 80 and 443 TCP, but without DNS I've hopefully limited how much it can do.

= DNS Whitelist in BIND with RPZ
 :hp-tags: DNS, Filtering, Firewall, Security

Restricting DNS queries to a specific list of domains.

I recently got a Samsung 'smart' TV which is very nice to look at.

Unfortunately there have been numerous security and privacy issues with smart TVs of all kinds, and Samsung in http://www.bbc.com/news/technology-31296188[particular].  So being predictably paranoid I immediately blocked the TV's IP address on my router to stop it getting to the internet.

As it turns out however, the built-in Netflix app on the TV is my only option for 4k Netflix (my HTPC was out due to not having a Kaby Lake chip).

So I found myself in a situation where I needed to allow the TV get out to the internet, despite my misgivings.

But this got me thinking - could I somehow limit it's access to just Netflix?  I initally tried an IP-based ACL on the router, but there were some issues with that so I began to wonder was there a DNS-based approach I could take?

=== Enter DNS RPZ

I am relatively familiar with https://www.isc.org/downloads/bind[ISC Bind] having used it down through the years, and one feature in particular suggested it might help - Response Policy Zones.

Basically RPZ can be used to create a DNS "firewall," limiting what domains can be resolved.  There is plenty of information online about how this can be set up, however I didn't find anything specifically explaining how to do what I needed (a total blacklist with only a very small whitelist of domains).

Turns out it's fairly easy to do.

=== Bind Configuration

The first step is to get a basic Bind resolver up and running.  I did this with a Ubuntu 16.04 system.

I then configured a 'response-policy' block in the 'options' section of my named.conf (on my particular system I did it in /etc/bind/named.conf.options).  This lists two RPZ zones which are used to define what queries to filter.  The key thing here is that RPZ checks zones in the order they are listed - this is key to creating a whitelist as opposed to a blacklist.  A single line is required:

 response-policy { zone "rpz.whitelist"; zone "rpz"; };

All queries will then be filtered based on the response policy zones listed.  If a match is found in the first (rpz.whitelist) then that will be used, otherwise the second one (rpz) will be checked.

The Bind server needs to be configured as authorititive master for these zones, similar to a standard zone, although with "allow-query" set to none.  Again this is in named.conf (in my case /etc/bind/named.conf.default-zones):

 zone "rpz.whitelist" {
    type master;
    file "/etc/bind/db.rpz.whitelist";
    allow-query { none; };
    allow-transfer { none; };
 };

 zone "rpz" {
    type master;
    file "/etc/bind/db.rpz";
    allow-query { none; };
    allow-transfer { none; };
 };

As can be seen the zone definitions reference the location of the zone files for each.  The files are created as follows, using the RPZ syntax.  The first zone, rpz.whitelist, is where to define the domains we want to allow.  In my case it looks like this:

_/etc/bind/db.rpz.whitelist_:
....
$TTL 60
@            IN    SOA  localhost. root.localhost.  (
                      4   ; serial
                      3H  ; refresh
                      1H  ; retry
                      1W  ; expiry
                      1H) ; minimum

                      IN     NS      localhost.

 netflix.com                 CNAME   rpz-passthru.
 *.netflix.com               CNAME   rpz-passthru.

 nflximg.com                 CNAME   rpz-passthru.
 *.nflximg.com               CNAME   rpz-passthru.

 nflximg.net                 CNAME   rpz-passthru.
 *.nflximg.net               CNAME   rpz-passthru.
....

Note that for each domain I have included the 'apex' record, and also a wildcard to catch all sub-domains.  In each case they are listed as CNAME records pointing to rpz-passthru, which is the RPZ syntax to tell Bind to allow queries for them.

The second RPZ zone file is created as follows.  This is configured for all sub-domains of the root zone, with a CNAME pointing to "." (which tells RPZ to return NXDOMAIN for such a lookup).  As the trailing dot (root zone) is left out of entries in RPZ zones, an asterix on it's own is all that is needed to represent subdomains of the DNS root:

_/etc/bind/db.rpz_:
....
$TTL 60
@            IN    SOA  localhost. root.localhost.  (
                     4   ; serial
                     3H  ; refresh
                     1H  ; retry
                     1W  ; expiry
                     1H) ; minimum

             IN      NS    localhost.

*                    CNAME .
....

With the config in place I was able to reload Bind and check if it was working.

=== Results

So does it work.  If I try to resolve a random domain I get an NXDOMAIN response:

....
topranks@dnsvm:~$ dig A www.samsung.com @localhost

; <<>> DiG 9.10.3-P4-Ubuntu <<>> A www.samsung.com @localhost
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 14003
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 2

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.samsung.com.		IN	A
....

And if I try for a sub-domain of netflix.com I get a valid response:

....
topranks@dnsvm:~$ dig A www.netflix.com @localhost

; <<>> DiG 9.10.3-P4-Ubuntu <<>> A www.netflix.com @localhost
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59390
;; flags: qr rd ra; QUERY: 1, ANSWER: 10, AUTHORITY: 4, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.netflix.com.		IN	A

;; ANSWER SECTION:
www.netflix.com.	1800	IN	CNAME	www.geo.netflix.com.
www.geo.netflix.com.	1800	IN	CNAME	www.eu-west-1.prodaa.netflix.com.
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.209.165.126
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.19.164.15
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.208.178.51
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.209.156.83
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.208.202.184
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.208.15.72
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.208.81.52
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.208.174.58
....

=== Additions for my Smart TV case

In addition to the above I changed the ACL on for traffic coming from the TV to only allow TCP on ports 80 and 443, which is enough for Netflix, but importantly blocks the TV from using any external DNS (even in normal circumstances it looks like the TV uses 8.8.8.8 in addition to any DNS server you give it yourself.)

Finally on the TV I changed the DNS server and sure enough the TV thinks something is wrong with DNS:

image::https://cloud.githubusercontent.com/assets/4465905/26027929/bd59e8b2-380e-11e7-81b1-b8b2b8fd2ffe.JPG[Samsung Error Message]

So far so good, and yes the Netflix app still works fine.  Looking closely at my Bind logs I can see what's happening:

....
Apr 20 17:42:27 dnsvm named[7369]: 13-May-2017 17:42:27.003 queries: info: client 192.168.240.42#40665 (art-0.nflximg.net): query: art-0.nflximg.net IN A + (192.168.240.32)
Apr 20 17:42:27 dnsvm named[7369]: 13-May-2017 17:42:27.003 rpz: info: client 192.168.240.42#40665 (art-0.nflximg.net): rpz QNAME PASSTHRU rewrite art-0.nflximg.net via art-0.nflximg.net.rpz.netflix
Apr 20 17:42:27 dnsvm named[7369]: 13-May-2017 17:42:27.766 queries: info: client 192.168.240.42#34179 (ns11.whois.co.kr): query: ns11.whois.co.kr IN A + (192.168.240.32)
Apr 20 17:42:27 dnsvm named[7369]: 13-May-2017 17:42:27.766 rpz: info: client 192.168.240.42#34179 (ns11.whois.co.kr): rpz QNAME NXDOMAIN rewrite ns11.whois.co.kr via ns11.whois.co.kr.rpz
Apr 20 17:42:29 dnsvm named[7369]: 13-May-2017 17:42:29.031 queries: info: client 192.168.240.42#59989 (time.samsungcloudsolution.com): query: time.samsungcloudsolution.com IN A + (192.168.240.32)
Apr 20 17:42:29 dnsvm named[7369]: 13-May-2017 17:42:29.031 rpz: info: client 192.168.240.42#59989 (time.samsungcloudsolution.com): rpz QNAME NXDOMAIN rewrite time.samsungcloudsolution.com via time.samsungcloudsolution.com.rpz
Apr 20 17:42:29 dnsvm named[7369]: 13-May-2017 17:42:29.033 queries: info: client 192.168.240.42#36357 (time.samsungcloudsolution.com): query: time.samsungcloudsolution.com IN A + (192.168.240.32)
Apr 20 17:42:29 dnsvm named[7369]: 13-May-2017 17:42:29.033 rpz: info: client 192.168.240.42#36357 (time.samsungcloudsolution.com): rpz QNAME NXDOMAIN rewrite time.samsungcloudsolution.com via time.samsungcloudsolution.com.rpz
....

So yeah, probably not ideal as the TV can still get out to the internet, at least on 80 and 443 TCP, but without DNS I've hopefully limited how much it can do.