<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Meteopress</title>
    <description>The latest articles on DEV Community by Meteopress (@meteopress).</description>
    <link>https://dev.to/meteopress</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F813%2Ff194a4a6-e626-455b-8646-831e6dc9996e.jpg</url>
      <title>DEV Community: Meteopress</title>
      <link>https://dev.to/meteopress</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/meteopress"/>
    <language>en</language>
    <item>
      <title>Granular access control to Google Cloud Storage objects using IAM Conditions</title>
      <dc:creator>Kuba Bartel</dc:creator>
      <pubDate>Fri, 20 Dec 2019 22:36:15 +0000</pubDate>
      <link>https://dev.to/meteopress/granular-access-control-to-cloud-storage-objects-using-iam-conditions-3m7n</link>
      <guid>https://dev.to/meteopress/granular-access-control-to-cloud-storage-objects-using-iam-conditions-3m7n</guid>
      <description>&lt;p&gt;At Meteopress we leverage Google Cloud Storage very intensively. Due to its serverless characteristics and unbeatable performance and reliability, it often makes a core part of our services. More traditionally we also use it as an unlimited data storage and for serving static website resources.&lt;/p&gt;

&lt;p&gt;But one feature we missed deeply - the ability to limit access to "directories" (subpaths) in Cloud Storage Bucket. Although Cloud IAM permissions had already been a very powerful mechanism, there was no possible way to bound each application (service account) to specific parts of a bucket.&lt;/p&gt;

&lt;p&gt;Practicing &lt;a href="https://en.wikipedia.org/wiki/Principle_of_least_privilege" rel="noopener noreferrer"&gt;least privilege principle&lt;/a&gt; we see a lot of sense in controlling shared bucket access - mainly in cases when production and experimental services meet on the same bucket resource.&lt;/p&gt;

&lt;p&gt;This superpower comes with brand new &lt;a href="https://cloud.google.com/storage/docs/access-control/using-iam-permissions#conditions-iam" rel="noopener noreferrer"&gt;Cloud IAM Conditions&lt;/a&gt; feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  Satellite processing service
&lt;/h2&gt;

&lt;p&gt;To demonstrate &lt;em&gt;Cloud IAM Conditions&lt;/em&gt; capabilities the following lines are going to describe and simulate a simplified satellite image processing service. The service continuously reads data downloaded from our satellite dish and processes each file to render enhanced images. We need the service to be able to read all incoming data and write processed data to a specified Cloud Storage "directory". After each new file is processed, the manifest file is updated to contain the lastest image metadata.&lt;/p&gt;

&lt;p&gt;The service is using &lt;code&gt;iamconditionsdemo&lt;/code&gt; bucket which is created with &lt;em&gt;uniform bucket-level permissions&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading data
&lt;/h2&gt;

&lt;p&gt;In the beginning, the service cannot read any data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; gsutil cp gs://iamconditionsdemo/satellite/raw/12_49.jpg .

ServiceException: 401 Anonymous caller does not have storage.objects.get access to iamconditionsdemo/satellite/12_49.jpg.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cloud Storage bucket is not publicly accessible so the service is going to use a service account to identify itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; gcloud auth activate-service-account --key-file gcp_credentials.json

Activated service account credentials for: [iamconditionstest@meteopress-radars.iam.gserviceaccount.com]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We assign &lt;em&gt;Storage Object Viewer&lt;/em&gt; role in bucket's permissions panel to the service account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fsbs2h81llfynu22k7sha.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fsbs2h81llfynu22k7sha.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now the service is able to read objects from the bucket. It has access to all of the objects no matter their name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; gsutil cp gs://iamconditionsdemo/satellite/raw/12_49.jpg .

Copying gs://iamconditionsdemo/satellite/raw/12_49.jpg...
- [1 files][835.5 KiB/835.5 KiB]
Operation completed over 1 objects/835.5 KiB.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Writing data
&lt;/h2&gt;

&lt;p&gt;After our service processes any given file it needs to store a new object with &lt;code&gt;satellite/processed/&lt;/code&gt; path prefix. This operation is not allowed at the moment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gsutil cp 12_49_processed.jpg gs://iamconditionsdemo/satellite/processed/12_49.jpg

Copying file://12_49_processed.jpg [Content-Type=image/jpeg]...
AccessDeniedException: 403 iamconditionstest@meteopress-radars.iam.gserviceaccount.com does not have storage.objects.create access to iamconditionsdemo/satellite/processed/12_49.jpg.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To allow object writes a service account can obtain &lt;em&gt;Storage Object Creator&lt;/em&gt; role. But the role actually allows any object to be written to the bucket. Any potentially dangerous write can appear and for example, contaminate our input dataset by creating an object starting with &lt;code&gt;satellite/raw/&lt;/code&gt; pathname.&lt;/p&gt;

&lt;p&gt;Cloud IAM Conditions are the right tool to prevent those unwanted writes. We can limit the permission to write an object just to specified object paths. This can be achieved by clicking on &lt;em&gt;Add condition&lt;/em&gt; besides the IAM role.&lt;/p&gt;

&lt;p&gt;Using &lt;em&gt;Edit condition&lt;/em&gt; dialog we set &lt;em&gt;Type&lt;/em&gt; to be a cloud storage object and resource &lt;em&gt;Name&lt;/em&gt; to filter object names by a prefix. According to the &lt;a href="https://cloud.google.com/storage/docs/key-terms#resource-name" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; object's resource name has the following form &lt;code&gt;projects/_/buckets/[BUCKET_NAME]/objects/[OBJECT_NAME]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fctoijfwrjbiis2ndly23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fctoijfwrjbiis2ndly23.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or we can switch to write the rule in the built-in text editor using Common Expression Language.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fpnwwsqt0gljqz709kxlh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fpnwwsqt0gljqz709kxlh.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The service is now able to write objects as required.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; gsutil cp 12_49_processed.jpg gs://iamconditionsdemo/satellite/processed/12_49.jpg

Copying file://12_49_processed.jpg [Content-Type=image/jpeg]...
\ [1 files][835.5 KiB/835.5 KiB]
Operation completed over 1 objects/835.5 KiB.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the same time, it can't write any objects out of &lt;code&gt;satellite/processed&lt;/code&gt; "directory".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; gsutil cp 12_49_processed.jpg gs://iamconditionsdemo/satellite/raw/12_49_processed.jpg

Copying file://12_49_processed.jpg [Content-Type=image/jpeg]...
AccessDeniedException: 403 iamconditionstest@meteopress-radars.iam.gserviceaccount.com does not have storage.objects.create access to iamconditionsdemo/satellite/raw/12_49_processed.jpg.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Updating manifest
&lt;/h2&gt;

&lt;p&gt;After each new image is processed its metadata needs to be saved to the predefined manifest file &lt;code&gt;satellite/manifest_processed.json&lt;/code&gt;. This object is not writable at the moment.&lt;/p&gt;

&lt;p&gt;Since &lt;em&gt;Storage Object Creator&lt;/em&gt; role doesn't give "storage.objects.delete" access (which is necessary to rewrite an object) we are going to add &lt;em&gt;Storage Object Admin&lt;/em&gt; permission just to &lt;code&gt;satellite/manifest_processed.json&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;"Unfortunately" the &lt;code&gt;iamconditionstest&lt;/code&gt; bucket was created with &lt;em&gt;uniform bucket-level permissions&lt;/em&gt; so we can't simply update object's permissions (not even mentioning it doesn't exist yet). IAM Conditions can be used again.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F3ojy4cm13xyzpp9iqk1o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F3ojy4cm13xyzpp9iqk1o.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now the manifest file can be created or updated after each image is processed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; gsutil cp manifest.json gs://iamconditionsdemo/satellite/manifest_processed.json

Copying file://manifest.json [Content-Type=application/json]...
/ [1 files][   22.0 B/   22.0 B]
Operation completed over 1 objects/22.0 B.

...manifest updated...

&amp;gt; gsutil cp manifest.json gs://iamconditionsdemo/satellite/manifest_processed.json

Copying file://manifest.json [Content-Type=application/json]...
/ [1 files][   44.0 B/   44.0 B]
Operation completed over 1 objects/44.0 B.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This illustrational use case demonstrates how &lt;em&gt;Cloud IAM Conditions&lt;/em&gt; can be used to limit a service account's access on a granular Cloud Storage Bucket level. In reality, we use multiple buckets to better segregate raw and processed data but principals stay the same.&lt;/p&gt;

&lt;p&gt;Cloud IAM Conditions are going to help us better control access to particular Cloud Storage resources and we can assure each service is not (re)writing data it shouldn't.&lt;/p&gt;

&lt;p&gt;We can also use Cloud IAM Conditions for our customers' service accounts which they use to read a bucket with data they are subscribed to. Now we don't have to copy datasets to each domain bucket but we can set correct access with IAM Conditions based on a customer's subscription.&lt;/p&gt;

&lt;p&gt;Cloud IAM Conditions are not limited just to the Cloud Storage resource type. The &lt;a href="https://cloud.google.com/iam/docs/conditions-overview#supported-services" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; describes other resources that can be controlled.&lt;/p&gt;

&lt;p&gt;Unfortunately, there is no Terraform support yet.&lt;/p&gt;

&lt;p&gt;What is your use case for &lt;em&gt;Cloud IAM Conditions&lt;/em&gt;?&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>gcp</category>
      <category>cloudstorage</category>
      <category>iam</category>
    </item>
  </channel>
</rss>
