<?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>Forem: Alexandre Bruffa</title>
    <description>The latest articles on Forem by Alexandre Bruffa (@alexandrebruffa).</description>
    <link>https://forem.com/alexandrebruffa</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%2Fuser%2Fprofile_image%2F1038754%2Faed4f95d-7dde-4c71-8dbd-7f1edaa17308.jpg</url>
      <title>Forem: Alexandre Bruffa</title>
      <link>https://forem.com/alexandrebruffa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/alexandrebruffa"/>
    <language>en</language>
    <item>
      <title>Generative AI With Amazon Bedrock and Unity3D</title>
      <dc:creator>Alexandre Bruffa</dc:creator>
      <pubDate>Fri, 06 Oct 2023 23:12:18 +0000</pubDate>
      <link>https://forem.com/aws-builders/generative-ai-with-amazon-bedrock-and-unity3d-22n7</link>
      <guid>https://forem.com/aws-builders/generative-ai-with-amazon-bedrock-and-unity3d-22n7</guid>
      <description>&lt;p&gt;A few days ago, Amazon made a big announcement: the service &lt;strong&gt;Bedrock&lt;/strong&gt; was finally released.&lt;/p&gt;

&lt;p&gt;If you missed the news, here it is: Amazon decided to enter massively into the generative AI field and invested in the company &lt;a href="https://www.cnbc.com/2023/09/25/amazon-to-invest-up-to-4-billion-in-anthropic-a-rival-to-chatgpt-developer-openai.html" rel="noopener noreferrer"&gt;Anthropic for $4 billion&lt;/a&gt; in order to compete with popular AI services like ChatGPT, Dall-E, MidJourney, etc. The first proposal of Amazon is Bedrock, a fully managed AI service that offers multiple foundational models such as Claude, Jurassic, and Stable Diffusion XL, among others.&lt;/p&gt;

&lt;p&gt;In my previous articles, I created Unity3D applications communicating with &lt;a href="https://betterprogramming.pub/i-made-chatgpt-talk-using-unity3d-and-aws-b0e83e6cce66" rel="noopener noreferrer"&gt;ChatGPT&lt;/a&gt; and &lt;a href="https://medium.com/better-programming/generating-ai-images-with-dall-e-aws-and-unity3d-33e9b77a2b5d" rel="noopener noreferrer"&gt;Dall-E&lt;/a&gt;. Let's do the same with Bedrock!&lt;/p&gt;

&lt;p&gt;Do you prefer something more interactive instead of reading? Check my video!&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/kzKxuGhdeZM"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  General Architecture
&lt;/h2&gt;

&lt;p&gt;Here is the general architecture of our application:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnr16hen5igebbofsmf0k.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnr16hen5igebbofsmf0k.png" alt="Architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We use 3 Amazon services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API Gateway to create, expose, and consume endpoints.&lt;/li&gt;
&lt;li&gt;Lambda to receive the client's requests and communicate with Bedrock.&lt;/li&gt;
&lt;li&gt;Bedrock to generate answers based on the client's prompts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to get further adding a login mechanism with Cognito, please refer to my previous article: &lt;a href="https://betterprogramming.pub/i-made-chatgpt-talk-using-unity3d-and-aws-b0e83e6cce66" rel="noopener noreferrer"&gt;Connecting Unity3D, AWS, and ChatGPT Together&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bedrock
&lt;/h2&gt;

&lt;p&gt;First, we have to enable the foundational models we want to use. By default, all the models are disabled. Go to the Bedrock console and enable the models you will use in the model access section. If you have an updated payment method, activating the models only takes a few minutes.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqyfnvgqwhn4oj3gf18ep.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqyfnvgqwhn4oj3gf18ep.png" alt="Model access section in the Bedrock console"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you don't enable the models in the Bedrock console, you will receive this error in Lambda:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;An error occurred (AccessDeniedException) when calling the InvokeModel operation: Your account is not authorized to invoke this API operation.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Lambda, Boto3 and Bedrock
&lt;/h2&gt;

&lt;p&gt;If you follow my work, you know I'm a Python guy, so I will use the Python SDK for AWS, &lt;a href="https://dev.tourl"&gt;Boto3&lt;/a&gt;. Good news: &lt;a href="https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock.html" rel="noopener noreferrer"&gt;Bedrock is available&lt;/a&gt; on Boto3; bad news: Lambda runs an old version of Boto3 in which Bedrock does not exist yet.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Here is a workaround:&lt;/strong&gt; creating a new Lambda layer with an up-to-date version of Boto3. This is how to do it:&lt;/p&gt;

&lt;p&gt;1) In PyCharm, create a new project and install boto3 in a new virtual environment. Boto3 and all the dependencies will be installed.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fny9ettalckocrk7qetf8.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fny9ettalckocrk7qetf8.png" alt="PyCharm project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2) Go to the venv folder of your project and copy the lib folder into a new folder called python. Then, zip it.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdu3tbjsujt2wougzjsz0.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdu3tbjsujt2wougzjsz0.png" alt="venv folder"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3) Go to the Layers section of the Lambda console and create a new layer. Upload the zip file we have created before and choose the same Python version as your local Python virtual environment for the runtime.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsvddls15zr8damnwkkxh.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsvddls15zr8damnwkkxh.png" alt="Creating a new Layer"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The Lambda Functions
&lt;/h2&gt;

&lt;p&gt;We create 2 Lambda functions, one for text generation and the other one for image generation, both with the same version as previously for the runtime (In my case, Python 3.9), and we add the layer we have created before.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbqmc3wjnj2i8gm6k21s0.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbqmc3wjnj2i8gm6k21s0.png" alt="Adding a new layer to the Lambda function"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  The text generation function
&lt;/h3&gt;

&lt;p&gt;For the text generation, I use the Claude model and implement it as described in the &lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/api-methods-run-inference.html" rel="noopener noreferrer"&gt;Amazon documentation&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;h3&gt;
  
  
  The image generation function
&lt;/h3&gt;

&lt;p&gt;For the image generation, I use the Stable Diffusion XL model and implement it, as described in the &lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/api-methods-run-inference.html" rel="noopener noreferrer"&gt;Amazon documentation&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Note that the model IDs can be found in the &lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids-arns.html" rel="noopener noreferrer"&gt;Bedrock documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Lambda Policy
&lt;/h3&gt;

&lt;p&gt;In order to allow Lambda to invoke a Bedrock model, we create a new managed policy and add it to the Lambda functions roles:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkcmkzruiqjigl2p1szk1.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkcmkzruiqjigl2p1szk1.png" alt="Policy"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  API Gateway
&lt;/h2&gt;

&lt;p&gt;In the API Gateway console, we create a new REST API with 2 resources: &lt;code&gt;image&lt;/code&gt; and &lt;code&gt;text&lt;/code&gt;. Each resource has a post method integrating with the Lambda functions we have created before.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0q5wtwcaz167plptac14.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0q5wtwcaz167plptac14.png" alt="API resources"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When deploying the API, you will be asked to create a new stage. After the creation of the stage, the final endpoint will be shown. You will have to use this URL in the Unity client to perform the request.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe4mpmk791xaylqkxcxjp.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe4mpmk791xaylqkxcxjp.png" alt="API stages"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Unity Client
&lt;/h2&gt;

&lt;p&gt;The Unity client allows the user to send a message to generate a text or an image as an answer:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe6dhwukq9il4vddybdsv.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe6dhwukq9il4vddybdsv.png" alt="Unity client"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling the request
&lt;/h3&gt;

&lt;p&gt;First, we need to create serializable classes to embed the sending and receiving data:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Sending a request in Unity is an asynchronous process. Therefore, we create a coroutine that sends the request to the server:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Dealing with the generated image
&lt;/h3&gt;

&lt;p&gt;If we ask for an image generation, the result sent by Bedrock is a &lt;code&gt;base64&lt;/code&gt; image. To show it on the Unity UI, we must convert it into bytes and create a &lt;code&gt;Texture2D&lt;/code&gt;. Then, we assign the texture to the &lt;code&gt;RawImage&lt;/code&gt; component of the UI.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Result
&lt;/h2&gt;

&lt;p&gt;Here is the result with text and image generations:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvirl8upuljl5zdqv5jjb.gif" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvirl8upuljl5zdqv5jjb.gif" alt="Image description"&gt;&lt;/a&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4yxit9v75yz00hvpzv4k.gif" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4yxit9v75yz00hvpzv4k.gif" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Costs
&lt;/h2&gt;

&lt;p&gt;Let's check with the &lt;a href="https://calculator.aws/#/" rel="noopener noreferrer"&gt;AWS Calculator&lt;/a&gt; and the &lt;a href="https://aws.amazon.com/bedrock/pricing/" rel="noopener noreferrer"&gt;Bedrock pricing sheet&lt;/a&gt; what our system cost would be for a very pessimistic scenario: you love the app, and you perform &lt;strong&gt;2,000 requests a month&lt;/strong&gt;. 1,000 for text generation with the Claude model and 1,000 for image generation with Stable Diffusion XL.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;API Gateway&lt;/strong&gt;: With 2,000 requests to our REST API, the monthly cost is &lt;strong&gt;0,01 USD&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lambda&lt;/strong&gt;: With 2,000 requests with an average time of 5 seconds and 512 MB of memory allocation, the monthly cost is &lt;strong&gt;0.08 USD&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bedrock&lt;/strong&gt;: 1,000 text generations by month with a maximum of 300 output tokens and 20 input tokens per request would result, in the worst case, in &lt;strong&gt;$0.2204 + $9.804&lt;/strong&gt;. 1,000 image generations would give us a bill of &lt;strong&gt;$18&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Total&lt;/strong&gt;: The total bill for our system would be approximately &lt;strong&gt;28 USD&lt;/strong&gt; monthly. It's quite affordable!&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Using Bedrock is very intuitive, and integrating it with other Amazon services is absolutely straightforward. The fact that Bedrock is an in-house product makes the integration easier: there is no need for API keys or external requests to make it work, resulting in greater performance and security.&lt;/p&gt;

&lt;p&gt;Every code of this article has been tested using Unity 2021.3.3 and Visual Studio Community 2022 for Mac. The mobile device I used to run the Unity app is a Galaxy Tab A7 Lite with Android 11.&lt;/p&gt;

&lt;p&gt;Thanks for reading until the end!&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;Here is the resource mentioned in the article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://drive.google.com/file/d/1QWbbHsmMrHi9gKolXfRmwclMdK1Sg4Qm/view" rel="noopener noreferrer"&gt;Unity package&lt;/a&gt; of the application&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://gist.github.com/alexandre-bruffa/c876fe69e00b70b9830863e8c7f06eb2" rel="noopener noreferrer"&gt;text generation function&lt;/a&gt; in Python&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://gist.github.com/alexandre-bruffa/537e19a9ab05748ac77b4a10370cc20b" rel="noopener noreferrer"&gt;image generation function&lt;/a&gt; in Python&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>bedrock</category>
      <category>unity3d</category>
      <category>ai</category>
    </item>
    <item>
      <title>Connecting Unity3D with AWS services</title>
      <dc:creator>Alexandre Bruffa</dc:creator>
      <pubDate>Fri, 30 Jun 2023 00:43:57 +0000</pubDate>
      <link>https://forem.com/aws-builders/connecting-unity3d-with-aws-services-1poe</link>
      <guid>https://forem.com/aws-builders/connecting-unity3d-with-aws-services-1poe</guid>
      <description>&lt;p&gt;In my &lt;a href="https://medium.com/@alexandre.bruffa" rel="noopener noreferrer"&gt;last articles&lt;/a&gt;, I realized direct integrations between Unity3D and AWS using the AWS SDK for .NET. I generally don't dive into details about how the connection between Unity3D and the AWS services is made in order to focus on the primary topic. Still, it deserves a whole article because it’s not that simple!&lt;/p&gt;

&lt;p&gt;There are many ways to access AWS resources from Unity. In this article, I will summarize three of them: using an IAM user, using a Cognito guest user, and using a Cognito authenticated user.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;General considerations&lt;/strong&gt;: For this article, we will use the AWS SDK for .NET. Since Unity uses .NET Standard 2.1, you will need the .NET Standard 2.0 assemblies available &lt;a href="https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/net-dg-obtain-assemblies.html#download-zip-files" rel="noopener noreferrer"&gt;here&lt;/a&gt; and unzip the file in your Unity project's &lt;code&gt;Plugins&lt;/code&gt; folder. Since we will perform asynchronous calls, you will also need the &lt;a href="https://www.nuget.org/packages/Microsoft.Bcl.AsyncInterfaces/" rel="noopener noreferrer"&gt;AsyncInterfaces&lt;/a&gt; package.&lt;/p&gt;

&lt;p&gt;If you prefer to watch a video instead of reading this article, here you have!&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/IW1b30AbiLw"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Using an IAM User
&lt;/h2&gt;

&lt;p&gt;Suppose you want to allow a specific user (i.e., a third-party app) to upload files to one of your S3 buckets. However, you only want to give programmatic access without implementing a signup or login flow. Using an IAM user is a perfect fit in this case.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkchxzqnrlu7iha1e6lwl.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkchxzqnrlu7iha1e6lwl.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s simulate the process: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the S3 console, create a new S3 private bucket. I will call mine &lt;code&gt;awsresourcesbucket&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs888m0ep9zh10eqlj38i.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs888m0ep9zh10eqlj38i.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the IAM console, create an IAM user with programmatic access and create a new Access Key; you will be given an Access Key and a Secret Access Key. Once created, don't forget to copy the Secret Access Key. It is shown just one time!&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2oxkxj7tbyi934iup8w5.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2oxkxj7tbyi934iup8w5.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Attach a new policy to the IAM user. The policy gives the required permissions to write into the S3 bucket.&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5lc8xg2trygeilr90567.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5lc8xg2trygeilr90567.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In Unity, build an S3 Client thanks to the IAM user's Access Key and Secret Access Key, and upload the file.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Comments about the above code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We use the &lt;a href="https://assetstore.unity.com/packages/tools/integration/native-gallery-for-android-ios-112630" rel="noopener noreferrer"&gt;NativeGallery package&lt;/a&gt; to pick an image from the device.&lt;/li&gt;
&lt;li&gt;We use the &lt;a href="https://docs.aws.amazon.com/sdkfornet/latest/apidocs/items/MS3S3PutObjectAsyncPutObjectRequestCancellationTokenNET45.html" rel="noopener noreferrer"&gt;PutObjectAsync&lt;/a&gt; function as described in the &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/example_s3_PutObject_section.html" rel="noopener noreferrer"&gt;AWS documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;UploadFileAsync&lt;/code&gt; function is asynchronous; you can call it with the &lt;code&gt;await&lt;/code&gt; operator inside an &lt;code&gt;async&lt;/code&gt; function.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Using a Cognito Guest User
&lt;/h2&gt;

&lt;p&gt;You may remember my &lt;a href="https://medium.com/better-programming/building-a-real-time-multiplayer-game-with-unity3d-and-amazon-gamelift-228f706cfbec" rel="noopener noreferrer"&gt;last article&lt;/a&gt;, where I built a real-time multiplayer game with Unity3D and Amazon GameLift. The Unity client calls a Lambda function to start playing, and we want that everybody who has downloaded the game can play without being logged in. You can achieve it using guest users of a Cognito Identity Pool. &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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh15scz9u94vrlkdnysrz.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh15scz9u94vrlkdnysrz.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s simulate it: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the Lambda console, create a simple Lambda function returning a dummy value (I will call it &lt;code&gt;awsResourcesFunction&lt;/code&gt;). I will do it in Python, but it's up to you to choose your favorite programming language.&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk0wkz1sc40ckzxqk7zns.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk0wkz1sc40ckzxqk7zns.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the Cognito console, create a Cognito Identity Pool with guest access. During the Pool creation, you will be asked to create a new guest role; I will call them respectively &lt;code&gt;awsResourcesIdentityPool&lt;/code&gt; and &lt;code&gt;awsResourcesCognitoGuestRole&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm7snz8o3dprf849gh2nm.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm7snz8o3dprf849gh2nm.png" alt="Image description"&gt;&lt;/a&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe398k90pdigw401ftf87.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe398k90pdigw401ftf87.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Once the Identity Pool is created, enter the guest role and attach a new policy. The policy gives the required permissions to invoke the Lambda function we have created before.&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05lnedn5kd27s7mzmz8o.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05lnedn5kd27s7mzmz8o.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In Unity, we first build the AWS Credentials thanks to the Identity Pool ID and then the Lambda Client with those credentials.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Comments about the above code: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/API_InvokeAsync.html" rel="noopener noreferrer"&gt;AWS documentation&lt;/a&gt; indicates that the &lt;code&gt;InvokeAsync&lt;/code&gt; function has been deprecated, but remember that we are using the .NET Standard 2.0 assemblies, so it's valid for us!&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://docs.aws.amazon.com/sdkfornet/latest/apidocs/items/MLambdaLambdaInvokeAsyncStringNET45.html" rel="noopener noreferrer"&gt;InvokeAsync&lt;/a&gt; function is asynchronous; you can call it with the &lt;code&gt;await&lt;/code&gt; operator inside an &lt;code&gt;async&lt;/code&gt; function.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Using a Cognito Authenticated User
&lt;/h2&gt;

&lt;p&gt;Now imagine that you want to allow the players of your game to upload a profile picture, but you require a login to do it. This case is a bit more complex because your game will handle guest and authenticated users. You can achieve it by creating a User Pool and adding authenticated access to our Identity Pool.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frjso0sfckcavi7dyzr8r.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frjso0sfckcavi7dyzr8r.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's try:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the Cognito console, create a new User Pool. You also be asked to create an Application Client during the User Pool creation. Don't forget to enable the &lt;code&gt;ALLOW_USER_PASSWORD_AUTH&lt;/code&gt; as authentication flow. &lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcunhl5qtm22yglnej2n1.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcunhl5qtm22yglnej2n1.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For this example, we assume we already have a user registered and confirmed. Please take a look at this &lt;a href="https://medium.com/better-programming/signing-up-users-from-unity3d-to-aws-cognito-using-the-aws-sdk-for-net-4a45f3a5f1fc" rel="noopener noreferrer"&gt;article&lt;/a&gt; of mine to learn how to do it. &lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm3seoc33pv2qmlcc4228.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm3seoc33pv2qmlcc4228.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Then, go back to the Identity Pool we created before, click on "Add identity provider" of the Authenticated access section, choose "Amazon Cognito User Pool", and link the Cognito User Pool we have created previously. &lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbmhle53yzjf79l597e51.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbmhle53yzjf79l597e51.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go then to "Edit role", create a new role, and attach a new policy to the role (or you can reuse the policy we created for the IAM User). The policy gives the required permissions to write into the S3 bucket.&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgkd0fdu6w4c1l9h0ycer.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgkd0fdu6w4c1l9h0ycer.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In Unity, we first login to the Cognito User Pool with the user Credentials; a &lt;code&gt;Token ID&lt;/code&gt; is returned. Then we build the AWS Credentials thanks to the Identity Pool ID, and we add the login data to the AWS Credentials: the &lt;code&gt;Token ID&lt;/code&gt; and the User Pool &lt;code&gt;Provider Name&lt;/code&gt;. We can finally build the S3 Client with the AWS Credentials and upload a file. &lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Comments about the above code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We log in to the Cognito User Pool thanks to the &lt;a href="https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CognitoIdentityProvider/MCognitoIdentityProviderInitiateAuthInitiateAuthRequest.html" rel="noopener noreferrer"&gt;InitiateAuthAsync&lt;/a&gt; function.&lt;/li&gt;
&lt;li&gt;We add the login data to the AWS Credentials thanks to the &lt;a href="https://docs.aws.amazon.com/sdkfornet/latest/apidocs/items/MCognitoIdentityCognitoAWSCredentialsAddLoginStringStringNET45.html" rel="noopener noreferrer"&gt;AddLogin&lt;/a&gt; function.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Provider Name&lt;/code&gt; is the concatenation of the following: &lt;code&gt;cognito-idp.&lt;/code&gt; + region + &lt;code&gt;.amazonaws.com/&lt;/code&gt; + Cognito User Pool ID.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Connecting Unity3D with AWS services is challenging work; I hope that this article could help you!&lt;/p&gt;

&lt;p&gt;All ids and tokens shown in this article are fake or expired; if you try to use them, you will not be able to establish any connections.&lt;/p&gt;

&lt;p&gt;Every code of this article has been tested using Unity 2021.3.3 and Visual Studio Community 2022 for Mac. The mobile device I used to run the Unity app is a Galaxy Tab A7 Lite with Android 11.&lt;/p&gt;

&lt;p&gt;A special thanks to &lt;a href="https://www.instagram.com/niimde/" rel="noopener noreferrer"&gt;Gianca Chavest&lt;/a&gt; for designing the fantastic illustration.&lt;/p&gt;

</description>
      <category>unity3d</category>
      <category>csharp</category>
      <category>aws</category>
      <category>services</category>
    </item>
  </channel>
</rss>
