A couple of weeks ago I published a long delayed post on mis/using a bunch of OCI services (WAF, API Gateway, Functions, and Object Store) to serve up a simple website. If you haven't read that post I suggest going back and giving it a quick skim so this post makes sense
In that post I said "Don't worry - we'll switch it back to Private before we upload anything important." And in this post, I'll quickly cover how to do that. So we can move on to more fun stuff in the next post... or perhaps the one after that.
As a quick background for those who aren't familiar with what "Public" and "Private" mean to OCI Object Store. When you create a Bucket you need to choose a privacy setting:
One danger of a public Bucket is that anyone out on the internet can dig through the contents and retrieve anything they can find. There have been tons and tons and tons of cases where someone accidentally left a bucket public and not-so elite hackers (perhaps even including the well-known hacker 4chan) downloaded their data. Which is precisely why OCI defaults to Private, shows you a warning when you toggle it to Public, and why Cloud Guard has a Detector that checks for that and considers it a "Critical" level problem.
A second danger is that someone could have a botnet just start downloading your content over and over and over and drive your bandwidth bill up. OCI's free tier includes 10 TB of egress (as of this writing) and after that is still much cheaper than our competitors, but I'm a well-known cheapskate and I hate seeing people paying for stuff they don't need to.
When you change a bucket to Private any calls to retrieve objects (think files) need to be authenticated. But we don't want our end-users to need to have an account in our tenancy, sign in, and use any special APIs to access the website. We just want https://demosite.ociateam.com/ to serve up the content.
So how do we do that?
My code already uses the Resource Principal Signer so I don't need to make any changes to it. Since I was accessing a Public bucket I didn't need to do that but I had been thinking ahead. So all I need to do now is protect the bucket and give the Function access to objects in that specific bucket.
The steps we're going to take are:
There's already a public doc taking you through the steps so this blog post will be short and sweet.
First, you'll want to copy the OCID of the existing Function. Navigate to your Application, open the Function, and click the Copy link next to the OCID. Remember that both the Application and the Function itself have an OCID. You can use either one in this case but I'm going to use the Function.
Then Navigate to IAM Dynamic Groups and click the button to Create a new one.
GIve it a Name, a Description, and then paste in the following under Rule 1:
resource.id = 'ocid1.fnfunc.oc1.iad.aaaaaaaaacq______dnya'
Then update the OCID to that of your Function.
Dynamic Groups exist across your tenancy so we'll be able to use this group in a Policy anywhere.
Unlike with Dynamic Groups, an IAM policy does exist within a Compartment. Since we are talking about the right way to do things after you navigate to Policies be sure to select your Compartment on the left-hand side before clicking the Create Policy button.
The new-ish Policy Builder will help you write a simple Policy so go ahead and pick off the lists. Ultimately you should wind up with a screen that looks something like this:
This is a good start but it does allow this function to access any bucket in the Compartment. Which could be dangerous depending on how many other Buckets you have there. Let's switch to the Manual editor so we can tighten things down a little bit.
Click the toggle next to Policy Builder:
And you should see the two policies you just created in a free form text box:
Then add a where clause to the second one:
In my case, I called the bucket "demo" when I probably should have called it something like "demosite". And then what's worse is I stupidly hardcoded that into my Function's source code. I'll have to fix that later.
Navigate back to the Bucket and click the Edit Visibility button, toggle the radio button to Private and hit Save Changes.
That's it. We're done.
Open your browser and go back to your demo site URL. If you did everything right nothing should have changed!
Remember how I said that I made a stupid mistake in naming the bucket? And then compounded that mistake by hard coding the name of the bucket into the Function's source code? And how I really should fix that?
In the next post, I'm going to do precisely that. And I'll do it the right way.