<?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: Matthew Henderson</title>
    <description>The latest articles on Forem by Matthew Henderson (@mattchenderson).</description>
    <link>https://forem.com/mattchenderson</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%2F232866%2F9beda4df-c1a8-44cd-b625-d9e41f6d91bb.jpeg</url>
      <title>Forem: Matthew Henderson</title>
      <link>https://forem.com/mattchenderson</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mattchenderson"/>
    <language>en</language>
    <item>
      <title>Why I'm obsessed with dev containers</title>
      <dc:creator>Matthew Henderson</dc:creator>
      <pubDate>Mon, 11 May 2020 15:05:32 +0000</pubDate>
      <link>https://forem.com/mattchenderson/why-i-m-obsessed-with-dev-containers-2pf7</link>
      <guid>https://forem.com/mattchenderson/why-i-m-obsessed-with-dev-containers-2pf7</guid>
      <description>&lt;p&gt;&lt;em&gt;Or, "How I will never install the JDK on my laptop again."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;While setting up a dev environment and getting things just so &lt;em&gt;can&lt;/em&gt; be rather enjoyable, it also can be a chore, especially when you're just trying to get something done. So what if I told you you could pretty much forget about setting up your project's dev dependencies?&lt;/p&gt;

&lt;p&gt;Enter &lt;a href="https://code.visualstudio.com/docs/remote/containers"&gt;VS Code dev containers&lt;/a&gt;, easily one of my favorite things right now. And I want you to be as excited as I am. Now, as a disclaimer, I work for Microsoft and am going to talk about Microsoft tech, but I don't work on the team responsible for this, and my enthusiasm is genuine. Just ask all the people I work with who have had to suffer me realizing what I could do here.&lt;/p&gt;

&lt;p&gt;Dev containers allow the following to be true:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I can speed up setup of a new dev machine (or a reimaged one).&lt;/li&gt;
&lt;li&gt;I can empower anyone to immediately start working with an open source project.&lt;/li&gt;
&lt;li&gt;I can have have custom remote environments that I can leverage from anywhere.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  But my project doesn't use containers!
&lt;/h2&gt;

&lt;p&gt;Nor does it need to! Dev containers are just an option for how all the tooling used to work with your project gets made available. It doesn't impact how your code is hosted and run at the end of the day.&lt;/p&gt;

&lt;p&gt;Containers are just a way of having a set of dependencies that can be run anywhere. That's it. What's the old joke about containers? "People kept saying 'it works on my machine,' so we just decided to ship their machine.'" Joking aside, yes, this is exactly what I want. Let me have a standard dev machine I can always have, ready to go.&lt;/p&gt;

&lt;p&gt;That's all a dev container is. It's a little running environment that hosts all the stuff that I would start putting on a new dev box, other than an IDE. I still get to have my local VS Code in my existing OS, with all of my personalization choices. VS Code connects to that environment, and it looks just like I have all of the right tools with all of the right versions, even though I'm not installing any of those SDKs, CLIs, etc. in my host OS. I can just rely on the container.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's use one
&lt;/h2&gt;

&lt;p&gt;Ok, so there are some baseline dependencies you need to play with this stuff. Yes, I realize this is a little hypocritical given the stated mission. But these are dependencies I can live with, personally. And they're kind of point in time - more on that later.&lt;/p&gt;

&lt;p&gt;Install &lt;a href="https://code.visualstudio.com/"&gt;Visual Studio Code&lt;/a&gt;, &lt;a href="https://docker.com"&gt;Docker&lt;/a&gt;, and the &lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers"&gt;Remote Containers extension&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, let's do some development. I happen to work on &lt;a href="https://azure.microsoft.com/services/functions/"&gt;Azure Functions&lt;/a&gt;, and we're going to use that now, but despite the name, you do not need to be an Azure customer to do any of this, nor do you have to know anything about Functions or the language you pick below. We're just going to do the basics to prove out the container, and I'll walk you through all of it.&lt;/p&gt;

&lt;p&gt;Choose one of the below options that you are not currently set up to do. And if you're set up to do all of those already, then 1) I'd love to hear about that, and 2) just pick your favorite.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/mattchenderson/azure-functions-starter-csharp"&gt;Authoring C# Azure Functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mattchenderson/azure-functions-starter-java"&gt;Authoring Java Azure Functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mattchenderson/azure-functions-starter-javascript"&gt;Authoring Node.js Azure Functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mattchenderson/azure-functions-starter-powershell"&gt;Authoring PowerShell Azure Functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mattchenderson/azure-functions-starter-python"&gt;Authoring Python Azure Functions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Clone the repo or download the zip from your chosen link above, and then launch VS Code, opening that folder. (&lt;code&gt;code .&lt;/code&gt; from the terminal is how I normally go.) &lt;/p&gt;

&lt;p&gt;Once VS Code launches, it should prompt you to reopen the project in the dev container. You can also run &lt;code&gt;CTRL+SHIFT+P -&amp;gt; Remote-Containers: Reopen in container&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And now we wait a bit. Our environment is getting built because all of those repos use a local Dockerfile. Things can be a little faster if we had the images hosted on a registry somewhere, but this is more flexible. The image is cached locally, so this is only going to happen the once, but the build admittedly isn't the fastest thing in the world.&lt;/p&gt;

&lt;p&gt;VS Code will eventually launch into the remote context. You'll be able to see that the workspace is remote using a container! You also may notice that a few new extensions are in place. These are actually hosted by the container itself; if you switch to a different local project, you won't see them. Nothing has changed on your system other than a cached container image.&lt;/p&gt;

&lt;p&gt;So let's do something in our new environment. The repo you cloned has instructions for adding a function, but it already has one included. Let's run it. Hit &lt;code&gt;F5&lt;/code&gt; (or in the menu, &lt;code&gt;Run -&amp;gt; Start Debugging&lt;/code&gt;). You'll see the integrated terminal pop up if it hasn't already, and you'll see some logs pop up as the Functions runtime gets going. Notably, you'll see a list of HTTP-triggered functions, which has the one we just created.&lt;/p&gt;

&lt;p&gt;Go ahead and &lt;code&gt;Ctrl+click&lt;/code&gt; the localhost link there. It'll open your browser to a page that says "Please pass a name on the query string or in the request body." Add a &lt;code&gt;?name=DevContainer&lt;/code&gt; to the URL and hit that to get our glorious Hello World. Feel free to set breakpoints and play around with it!&lt;/p&gt;

&lt;p&gt;It's a simple example, sure, but you just went from zero to debugging a project in only a few steps. And you're now in a position to develop something that your system might not have been set up for before. And if you want to get rid of it, you can just remove the image, and it's like nothing was ever there.&lt;/p&gt;

&lt;h2&gt;
  
  
  But what if that container was... remote?
&lt;/h2&gt;

&lt;p&gt;So, this container doesn't actually have to be running on your development machine. Part of the reason dev containers are one of my favorite things is that &lt;a href="http://online.visualstudio.com/"&gt;Visual Studio Codespaces&lt;/a&gt; is one of my favorite things. If you happen to have access to the Visual Studio Codespaces preview, you can spin up your container there and just connect to it from any VS Code client or use the browser editor. This may or may not work with &lt;a href="https://github.com/features/codespaces"&gt;GitHub Codespaces&lt;/a&gt; - I haven't tried that yet.&lt;/p&gt;

&lt;p&gt;From your browser of choice, head to your &lt;a href="https://online.visualstudio.com/environments"&gt;environments dashboard&lt;/a&gt; and select "Create Codespace" (or in VS Code use &lt;code&gt;CTRL+SHIFT+P -&amp;gt; Codespaces: Create New Codespace&lt;/code&gt; and follow prompts). Go ahead and Choose "Default settings" and then paste in a link to a GitHub repo with your container and the project that will be mounted in. Give the environment a name, and then wait for the magic to happen. You'll be able to connect to the environment and get working right away.&lt;/p&gt;

&lt;p&gt;So remember those things I had you install to try things out? Well, going this route, we don't need Docker locally, and once you can do everything from the portal, we don't necessarily need VS Code and the Remote Container extension either. As long as I have an account, all I need is a browser to get to work on my projects. That's powerful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an image
&lt;/h2&gt;

&lt;p&gt;If I've sold you on the idea, you may be wondering how you can make these yourself. I'll admit that I cheated a little in creating the earlier samples, but you should, too.&lt;/p&gt;

&lt;p&gt;In a local project in VS Code, run &lt;code&gt;CTRL+SHIFT+P -&amp;gt; Remote-Containers: Add Development Container Configuration Files...&lt;/code&gt; This will prompt you with a list of containers for a variety of languages, which make a great place to start. Those are sourced from the &lt;a href="https://github.com/microsoft/vscode-dev-containers"&gt;vscode-dev-containers repo&lt;/a&gt;, and I certainly relied on the built-in Functions ones.&lt;/p&gt;

&lt;p&gt;The dev container is defined by the &lt;code&gt;devcontainer.json&lt;/code&gt;, which can specify a local &lt;code&gt;Dockerfile&lt;/code&gt; that has the environment all set up. It can also point to VS Code extensions that should be loaded, but I want to call attention to the &lt;code&gt;postCreateCommand&lt;/code&gt; option, which is great for initially resolving code dependencies with something like an &lt;code&gt;npm install&lt;/code&gt;. Full reference for the file can be found &lt;a href="https://code.visualstudio.com/docs/remote/containers#_devcontainerjson-reference"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Living with dev containers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Security
&lt;/h3&gt;

&lt;p&gt;One thing that gives me pause is knowing that I have to make sure the the image is patched and up to date. There are solutions for this, but it's something to be mindful of in general. There's also the question of if I can trust a container from someone else. I think about this somewhat similarly to how I think about trust of any tooling, or even package management. However, the trust relationship is a little different when I'm looking at a given project versus a tool the community has rallied behind and vetted.&lt;/p&gt;

&lt;p&gt;Regardless, I'm curious to see how the conversation evolves around these. There's also a lot to be said for having a dev container that helps bring along all the right and latest patched versions of requisite tools, too.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tips for managing local storage space
&lt;/h3&gt;

&lt;p&gt;If you're working from VS Code on your machine, the images that back your containers are cached locally. This is great! But they can also get kind of big, and that can be less great. I find that between dev containers and stuff I'm building for services, I fill up a disk fast. So it's good to periodically get rid of images you don't need. &lt;/p&gt;

&lt;p&gt;In your terminal, get your list of images with &lt;code&gt;docker images&lt;/code&gt;. Find what you want to remove and note its ID. You'll pass that into the next command, which removes the image &lt;code&gt;docker rmi &amp;lt;image_id&amp;gt;&lt;/code&gt;. There's a chance Docker might yell at you here because the image is being used by a stopped container. If you find yourself in that state, you can get rid of all stopped containers with &lt;code&gt;docker container prune&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing thoughts
&lt;/h2&gt;

&lt;p&gt;My sincerest thanks to the devcontainer and Codespaces team who supported me through early previews, and major congratulations to them on putting some truly awesome tech out into the world.&lt;/p&gt;

&lt;p&gt;I'm really excited to use dev containers wherever possible. Setting up demos? You bet. Experimenting with a new technology? Absolutely. Making things work consistently across machines I use? I see little downside.&lt;/p&gt;

&lt;p&gt;But my enthusiasm goes beyond personal productivity. This is a way to make a codebase more accessible to newcomers, and I truly hope it becomes common practice. I think a lot of us have made peace with the idea of losing some amount of time to setting up a machine, enlisting in a new codebase etc. But we now have tool to help folks avoid that productivity hit. If you maintain an open source project, consider adding one to make things more approachable (especially once GitHub Codespaces is more widely available). If you're part of a team that needs to onboard new members, look to this as a tool to make things easier and get them going faster.&lt;/p&gt;

&lt;p&gt;Related, I've got my eye on &lt;a href="https://cnab.io/"&gt;Cloud Native Application Bundles (CNAB)&lt;/a&gt;, which seems to do some of the same things, enabling anyone to deploy an app. That will probably be one of the next things I play with, and I have a feeling it will combine really well with dev containers.&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>containers</category>
      <category>github</category>
    </item>
    <item>
      <title>Automating virtual status syncs</title>
      <dc:creator>Matthew Henderson</dc:creator>
      <pubDate>Fri, 27 Mar 2020 15:08:39 +0000</pubDate>
      <link>https://forem.com/mattchenderson/automating-virtual-status-syncs-444d</link>
      <guid>https://forem.com/mattchenderson/automating-virtual-status-syncs-444d</guid>
      <description>&lt;p&gt;Status meetings can be a very helpful tool for a lot of teams. It's a chance for the team to identify and tackle issues that come up in the day-to-day of work. But sometimes a meeting can be a bit much, or other logistics get in the way.&lt;/p&gt;

&lt;p&gt;I've had good success with virtual status reporting over a couple of projects, and especially lately, I've had some folks asking how I do some of this. This post is just a quick summary of how I like to set things up using &lt;a href="https://products.office.com/microsoft-teams/group-chat-software" rel="noopener noreferrer"&gt;Microsoft Teams&lt;/a&gt;, &lt;a href="https://flow.microsoft.com/" rel="noopener noreferrer"&gt;Power Automate&lt;/a&gt;, and the &lt;a href="https://graph.microsoft.com" rel="noopener noreferrer"&gt;Microsoft Graph&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Disclaimers: I work at Microsoft and will be talking about Microsoft tech (although none that I work on), but the principles here should be applicable to other systems. However, it's also worth calling out that I'm speaking from a tech engineering background, which is not the only place these kinds of meetings happen, and this process may not translate to other industries.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  The threaded status discussion
&lt;/h1&gt;

&lt;p&gt;A simple but effective approach to virtual status is just using threads in team-chat where people post what they would otherwise say in an in-person status meeting. This can work surprisingly well, but one thing to caution is that it encourages posting without reading. At least in a meeting context, people are forced to listen to each other. That's a question of your team culture, though, and it's important to evaluate how you extract value from these status reports.&lt;/p&gt;

&lt;p&gt;Regardless, we need to start that thread. Generally speaking, you may want a designated channel for statuses, but it could be mixed into another channel. You can designate someone to create that initial post, but I much prefer to automate the process. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The goal:&lt;/strong&gt; Every workday, automatically start a thread in team-chat where participants can leave/read status info, and notify the channel so that they remember to post. Oh, and we should do this without code because why maintain that if I don't have to (I work in serverless tech, after all).&lt;/p&gt;

&lt;p&gt;This is the end result we're after:&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%2Fi%2Fns4ap8eshrhxwyxx0s2p.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%2Fi%2Fns4ap8eshrhxwyxx0s2p.PNG" alt="A new thread in teams starting a status conversation for the day"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Using Power Automate to create a thread in Teams
&lt;/h1&gt;

&lt;p&gt;My team uses Microsoft Teams, and for this kind of automation, I really like Power Automate (formerly called "Microsoft Flow"), as I can get a workflow up and running in no time. This post assumes some basic familiarity with Power Automate, but nothing you can't get by playing around with it for a few minutes.&lt;/p&gt;

&lt;p&gt;There's really only two pieces to the workflow we're exploring today:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have it kick off every weekday&lt;/li&gt;
&lt;li&gt;Create a new thread in the channel, with an @channel mention&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enabling that mention means that our flow will have a few more constituent steps, but overall it will still be relatively simple. By the time we're done, the overall structure of the flow should look something like this:&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%2Fi%2F3xanm2buu92lvfnidht3.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%2Fi%2F3xanm2buu92lvfnidht3.png" alt="Flow structure showing a recurrence, followed by 3 variable initializations, followed by a conditional, the "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Scheduling the post
&lt;/h2&gt;

&lt;p&gt;Flows can be set to run on a schedule, using the &lt;a href="https://docs.microsoft.com/power-automate/run-scheduled-tasks" rel="noopener noreferrer"&gt;Recurrence trigger&lt;/a&gt;. I want mine to run every weekday, typically at something like 7:00am PT, which still puts it in morning for pretty much all timezones we have team members in. If the target time is early for any team members though, just be mindful about mobile notifications that could wake someone up - the Teams app built-in quiet hours feature is something I heartily recommend.&lt;/p&gt;

&lt;p&gt;It would seem natural to set the "Frequency" field to "Day" here, but then weekends are included and you'd need an odd conditional check (&lt;br&gt;
&lt;code&gt;@contains('12345', string(dayOfWeek(addHours(utcNow(), -8))))&lt;/code&gt;). Better is to set the frequency to "Week,"  and under the "Advanced options" section, you can set "On these days" to to just the days you care about.&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%2Fi%2Fxygc7zd7xgw6lm7nfm64.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%2Fi%2Fxygc7zd7xgw6lm7nfm64.PNG" alt="Screenshot of the recurrence configuration"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Calling Teams from Power Automate
&lt;/h2&gt;

&lt;p&gt;Now, your first instinct may be to use the &lt;a href="https://flow.microsoft.com/connectors/shared_teams/microsoft-teams/" rel="noopener noreferrer"&gt;built-in Teams action&lt;/a&gt; for creating a post. By all means do; I always advocate for owning and maintaining less custom stuff. However, for my needs, I &lt;em&gt;really&lt;/em&gt; wanted the @mention capability so that there is a notification in the channel. The connector can't do that yet, but the &lt;a href="https://docs.microsoft.com/graph/api/channel-post-messages" rel="noopener noreferrer"&gt;Microsoft Graph API&lt;/a&gt; can. Fortunately, it's actually relatively easy to make an authenticated call to the Microsoft Graph using the &lt;a href="https://flow.microsoft.com/connectors/shared_webcontents/http-with-azure-ad/" rel="noopener noreferrer"&gt;HTTP with Azure AD connector&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;HTTP with Azure AD is a "Premium" connector, meaning it's not available in the free version of Power Automate&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So now all we need to do is figure out how to use that Teams API. The docs help a little bit, but I find I learn APIs best when I can play with them. It's time to break out the Graph Explorer.&lt;/p&gt;
&lt;h3&gt;
  
  
  Gathering your Teams configuration
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://developer.microsoft.com/graph/graph-explorer" rel="noopener noreferrer"&gt;Graph Explorer&lt;/a&gt; is a really nice environment for exploring the Microsoft Graph, either against sample data or against your own tenant. I used it to figure out the details of the create message API, but I've captured those throughout these steps so you don't have to (although you could certainly test out the payload using the Explorer).&lt;/p&gt;

&lt;p&gt;If you're planning to put this into practice, though, you still need some configuration values: the ID of your team and the ID/name of the channel you're creating the post in. I believe you can parse this information out of a channel link, but for me it's easier to get through the APIs, so here are the steps using Graph Explorer.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Within the Graph Explorer, hit the "Sign in with Microsoft" button and log in so you're working against your actual data.&lt;/li&gt;
&lt;li&gt;Run a GET against &lt;code&gt;https://graph.microsoft.com/v1.0/me/joinedTeams&lt;/code&gt; and search through the output for the team you're interested in. Make note of the &lt;code&gt;id&lt;/code&gt; field.&lt;/li&gt;
&lt;li&gt;Similarly, run a GET against &lt;code&gt;https://graph.microsoft.com/v1.0/teams/{team-id}/channels&lt;/code&gt;, replacing &lt;code&gt;{team-id}&lt;/code&gt; with the value you got in the previous step. As before, search through the output for the channel you want to post in, and grab the corresponding &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;displayName&lt;/code&gt; fields.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now we have our values, but we need to get them into the workflow. We'll create some variables at the top of the workflow. Right after the recurrence, add three "Initialize Variable" actions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One with the name "Team ID" with the "string" type, it's value being the team &lt;code&gt;id&lt;/code&gt; you collected earlier&lt;/li&gt;
&lt;li&gt;One with the name "Channel ID" with the "string" type, it's value being the channel &lt;code&gt;id&lt;/code&gt; you collected earlier&lt;/li&gt;
&lt;li&gt;One with the name "Channel Name" with the "string" type, it's value being the channel &lt;code&gt;displayName&lt;/code&gt; you collected earlier.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that the "Name" fields matter here as they are referenced later. Although the title of the card doesn't matter, I recommend renaming them for clarity (e.g., "Set Team ID"). &lt;/p&gt;

&lt;p&gt;For safety, I like to I add a conditional check to make sure the variables are all set to non-null values. Then I put the actions from the following section in the "yes" branch, and I can do some error logging in the "no" branch. This is optional, though, and you can just add the post creation as the next set of actions if you like living dangerously.&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%2Fi%2Fphwrq73ndldtv9w7wdg1.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%2Fi%2Fphwrq73ndldtv9w7wdg1.PNG" alt="Screenshot of variable initialization and the conditional check"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Creating the post
&lt;/h3&gt;

&lt;p&gt;To keep things a little simpler, I prefer to separate out the construction of the request body for our API call from the actual request action. To do that, we use the Compose action, which sets a new dynamic content we can reference later. Rename the action "Compose message" for the later lookup, and then set the "Inputs" field to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"subject"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@{variables('Channel Name')} status for @{formatDateTime(utcnow(),'yyyy/MM/dd')} (Automated post)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;p&amp;gt;&amp;lt;at id=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;0&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;@{variables('Channel Name')}&amp;lt;/at&amp;gt; Post what you've been working on and what you're working on today.&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;For conversations, create a new thread in the channel. Try not to actually &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;reply&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; to others in this thread to keep it easy to see. Extra flair: • (bullet) - work item; 🏃 - on-going work; 💪- stretch goal&amp;lt;/p&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"contentType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"html"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mentions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"mentionText"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@{variables('Channel Name')}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"mentioned"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"conversation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@{variables('Channel ID')}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"displayName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@{variables('Channel Name')}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"@{concat('conversationIdentityType@','odata.type')}"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#Microsoft.Teams.GraphSvc.conversationIdentityType"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"conversationIdentityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"channel"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;You may notice a &lt;code&gt;concat&lt;/code&gt; of static values in one of the keys there. This was me attempting to get around the value looking like an email. PowerAutomate won't let you share a workflow if it thinks there's an email in it. If that's a concern for you, note that the channelID resembles an email, too, so you may need to make a similar adjustment earlier on.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lastly, we need to use the HTTP with Azure AD connector to send that message. Create an action for that connector, and sign in as prompted. This creates a "connection," which is the identity used for the call. That means the post in Teams will show up under your name. Fill out the card as follows:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field name&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Method&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Post&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Url of the request&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://graph.microsoft.com/beta/teams/@{variables('Team ID')}/channels/@{variables('Channel ID')}/messages&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Headers&lt;/td&gt;
&lt;td&gt;Key: &lt;code&gt;Content-Type&lt;/code&gt;, Value: &lt;code&gt;application/json&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Body of the request&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@{outputs('Compose_message')}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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%2Fi%2Fvwpmny66ig4r9h1jchil.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%2Fi%2Fvwpmny66ig4r9h1jchil.png" alt="A screenshot of the HTTP with Azure AD card, filled in with the values from the table above"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And with that, the flow is complete. A post will land in the channel daily that people can respond to with their status.&lt;/p&gt;

&lt;h1&gt;
  
  
  How it's working for us
&lt;/h1&gt;

&lt;p&gt;I'd say this process has been going well, overall. It's by no means perfect, but the consensus from my team seems to be that this helps. I've found good success with using both threads and meetings when possible. I use a thread to capture things in advance from folks who may not be able to make a meeting, and then that's read out during the designated meeting time. For smaller teams where everyone is always at the meeting, the thread isn't that valuable day-to-day, but occasionally it helps us react to a sudden change or follow up on discussed topics.&lt;/p&gt;

&lt;p&gt;The threads have also had broader readership than I expected. For example, devs on my team will read the status thread that the PMs use. I should be clear that we'd never have a PM standup meeting, but we still want to communicate and coordinate with each other, and this fits the bill. The unintended side effect is that non-participants have felt better aware of what we're doing by being able to check in on what those threads are looking like.&lt;/p&gt;

&lt;p&gt;Looking forward, I'm playing with the idea of using "channel meetings," which is what I'm calling the Teams "Meet Now" feature. What's nice is that the meeting is visible in the channel, and anyone with access to it can just join. I'm looking into this for office hours and other applications, too, but it could be interesting in a status context.&lt;/p&gt;

&lt;p&gt;I hope that some of this helps or was interesting! Every team is different, and you'll have to find what works best for you. The process I've described here is a little more complicated than it needs to be just because I wanted the @mentions, and as soon as the Teams connector supports those, I'll be moving to it. Regardless, the key here was identifying a process that can work for the team, and then putting it into practice quickly with the tools I had on hand.&lt;/p&gt;

&lt;p&gt;Be well, and happy status reporting!&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>management</category>
      <category>agile</category>
    </item>
    <item>
      <title>They can't hack your servers if you don't have any servers, right?</title>
      <dc:creator>Matthew Henderson</dc:creator>
      <pubDate>Mon, 23 Sep 2019 22:18:57 +0000</pubDate>
      <link>https://forem.com/mattchenderson/they-can-t-hack-your-servers-if-you-don-t-have-any-servers-right-246a</link>
      <guid>https://forem.com/mattchenderson/they-can-t-hack-your-servers-if-you-don-t-have-any-servers-right-246a</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article is part of &lt;a href="https://dev.to/azure/serverless-september-content-collection-2fhb"&gt;#ServerlessSeptember&lt;/a&gt;. You'll find other helpful articles, detailed tutorials, and videos in this all-things-serverless content collection. New articles are published every day — that's right, every day — from community members and cloud advocates in the month of September.&lt;/p&gt;

&lt;p&gt;Find out more about how Microsoft Azure enables your Serverless functions at &lt;a href="https://docs.microsoft.com/azure/azure-functions/?WT.mc_id=servsept_devto-blog-cxa" rel="noopener noreferrer"&gt;https://docs.microsoft.com/azure/azure-functions/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you prefer videos, some of the content in this article is covered in talks I've given at a few ServerlessDays events (&lt;a href="https://www.youtube.com/watch?v=2Oq_U6J82ks" rel="noopener noreferrer"&gt;London 2018&lt;/a&gt;, &lt;a href="https://www.youtube.com/watch?v=rJBCRhrfnak" rel="noopener noreferrer"&gt;Tel Aviv 2019&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I end up talking a good bit about serverless security. And while I haven't yet gotten the exact question from the title of this post, there are definitely some &lt;em&gt;expectations&lt;/em&gt; that come up in these conversations. Yes, by choosing serverless, you have set a good baseline security posture. But serverless isn't some silver bullet that makes your app invulnerable. I think it's perfectly fair to ask: &lt;strong&gt;Do the servers even matter if they can hack your app?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Spoilers: they don’t.&lt;/em&gt; Our applications are more than our servers. They are collections of services. They are operational practices that we espouse. They are fallible in their own right.&lt;/p&gt;

&lt;p&gt;The moment you say the words "cloud security," it's almost guaranteed that someone is going to bring up the "shared responsibility model," which describes how some aspects of security are burden of the cloud provider and some are burden of the cloud customer. Here's how I like to draw 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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fjcmwa7km5omzvpwmm7fz.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%2Fjcmwa7km5omzvpwmm7fz.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are still plenty of things we need to be concerned with when building serverless apps. And at times I think the hype cycle and some confusion about serverless has led folks to forget that this is the case. I've long been fascinated by the concept of "risk compensation." The idea there is that if people feel safer, they take greater risks. The classic example is that cyclists wearing helmets are more likely to ride more aggressively in traffic than those without. So what do you think happens when we keep talking about "serverless" in terms of what we don't have to be concerned with?&lt;/p&gt;

&lt;h1&gt;
  
  
  Common pitfalls in serverless
&lt;/h1&gt;

&lt;p&gt;The Open Web Application Security Project (OWASP) publishes lists of &lt;a href="https://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project" rel="noopener noreferrer"&gt;the top 10 security vulnerabilities&lt;/a&gt;, and there's a scary trend that you see over the years: the list doesn't change much. That means we collectively are still really bad at these. And guess what? All of them still apply to serverless applications. The OWASP even has a handy &lt;a href="https://www.owasp.org/index.php/OWASP_Serverless_Top_10_Project" rel="noopener noreferrer"&gt;interpretation for serverless&lt;/a&gt;. You may think you would never create such vulnerabilities, but that's the surest path to making them.&lt;/p&gt;

&lt;p&gt;Let's look at some problems in action. Here's a nice little function that thanks someone for opening a pull request on GitHub:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;opened&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;done&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;comment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;body&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Thank you for your contribution! We will get to it shortly.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pull_request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;pr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pull_request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; submitted PR#&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;SendGitHubRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;comments_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// posting a comment&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;done&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;SendGitHubRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requestBody&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;request&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;githubCred&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Basic &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mattchenderson:8e254ed4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User-Agent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mattchenderson&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;githubCred&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;json&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;requestBody&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do you see it? Check where I assign &lt;code&gt;githubCred&lt;/code&gt;. I seem to have left some credentials in my source code! This is bad, but certainly it only happens to other people, right? Well, it's way more common than you think, but there are all sorts of tools to help with this. And it's worth calling out that this can happen with any traditional application. So why bring it up in the context of serverless?&lt;/p&gt;

&lt;p&gt;Well, most solutions you will see here rely on identity and permissions. Permissions are tough, especially when you're talking about them at the granularity of a function. In Azure, we have this concept called a “function app,” which is just a collection of functions that share code, config, or management. So if I group functions with different permission needs, I could end up granting all permissions to all functions. That’s violating the principle of least privilege, and this kind of overgrouping is extremely common. I should be splitting things up into different function apps where I can.&lt;/p&gt;

&lt;p&gt;So how about this code? What's wrong here?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;202&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bindings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outQueueMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;delete&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Please pass a name in the request body&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;done&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I would say that it's the fact that I'm just taking the input and passing the data downstream via a queue (via the &lt;code&gt;target&lt;/code&gt; property assignment). That's a problem because right now &lt;em&gt;we don't know what's downstream&lt;/em&gt;. Would you like to know? It's this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;Connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tedious&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="c1"&gt;//... Get from env vars&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;  
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Connected&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;//...&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;myQueueItem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myQueueItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;delete&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DELETE FROM Inventory WHERE ItemName='&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;myQueueItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;';&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
         &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);}&lt;/span&gt;  
        &lt;span class="p"&gt;});&lt;/span&gt;  
        &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execSql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;done&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why, that's a SQL injection vulnerability! This injection may seem extreme, but imagine this is a third-party dependency problem, or really anything else. Yes, this function should absolutely be validating input, but I think it's also fair to question the function that came before it. It could have been a better steward of the overall application by making sure it wasn't introducing malicious payloads for someone else to fall prey to.&lt;/p&gt;

&lt;p&gt;This is an uncomfortable idea for a lot of folks, and you sometimes see blame flying between teams deploying microservices into one application. If you're ever in that situation, please just remember the phrase "it's not my fault, but it is my responsibility." At the end of the day, it's a team effort, and application security is everyone's responsibility.&lt;/p&gt;

&lt;h1&gt;
  
  
  More secure serverless
&lt;/h1&gt;

&lt;p&gt;So what do we do? How do we set ourselves up for success with serverless security? It's an interesting question, because we don't have all of the same tools we might be used to from the serverfull days. That said, serverless platforms have evolved in terms of security features and networking options, and the serverless security tooling ecosystem has been maturing nicely.&lt;/p&gt;

&lt;p&gt;At the end of the day, the main adjustments I see teams needing to make are the same kinds of things you find in distributed systems conversations. But for a lot of teams, serverless is their big introduction to more distributed architectures. Observability is key to this, and there's lots of great conversations going on around serverless observability. If you're using Azure, be sure to set up &lt;a href="https://docs.microsoft.com/azure/azure-monitor/app/app-insights-overview" rel="noopener noreferrer"&gt;Application Insights&lt;/a&gt; for your apps.&lt;/p&gt;

&lt;p&gt;And in general, please leverage any of the security features built into your cloud provider! I keep finding folks that don't even know about things like &lt;a href="https://azure.microsoft.com/services/security-center/" rel="noopener noreferrer"&gt;Azure Security Center&lt;/a&gt; or &lt;a href="https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview" rel="noopener noreferrer"&gt;managed identities&lt;/a&gt;. Not everything is free, but there are a ton of capabilities that are, and some of them are as simple as flipping a switch.&lt;/p&gt;

&lt;p&gt;Also check what things can be plugged in to your DevOps pipeline. That's a fantastic place to centralize all sorts of security enforcement for your organization, and again, there are lots of things you can just flip a switch to enable. In general, there have been some really cool developments in the DevSecOps space. I'm seeing more and more applications of serverless technologies  as automation tools to help teams with their security posture. This is a very interesting trend, and I think there's a lot of promise here.&lt;/p&gt;

&lt;p&gt;And it's not the glamorous answer you might be hoping for, but the truth is that diligence and threat modeling are always good practices. We probably haven't been doing enough of that even in our existing apps, if we're being honest. I know I've been guilty of this. The most important thing is to be intentional about development. At its core, serverless is about productivity, but that doesn't mean we get to cut corners. Maybe some of the time we recover from certain operations can just be put toward improving our security practices.&lt;/p&gt;

&lt;h1&gt;
  
  
  Keep learning
&lt;/h1&gt;

&lt;p&gt;There's tons of great content out there if you want to learn more. I've found the following to be particularly helpful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=x9-JKHzLfjw" rel="noopener noreferrer"&gt;Practical Auth in a Serverless World&lt;/a&gt; by Andreas Grimm&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aka.ms/GettingStartedWithAppSec" rel="noopener noreferrer"&gt;Getting Started with AppSec&lt;/a&gt; by Tanya Janca&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://hackernoon.com/many-faced-threats-to-serverless-security-519e94d19dba" rel="noopener noreferrer"&gt;Many-Faced Threats to Serverless Security&lt;/a&gt; by Yan Cui&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://acloud.guru/series/serverlessconf-sf-2018/view/129c63e4-9cbf-9b90-d500-3193d5af9855" rel="noopener noreferrer"&gt;Calling $@*! on Security: A Cultural Challenge&lt;/a&gt; by Mark Nunnikhoven&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've also found both the serverless and DevSecOps communities to be super approachable in general. I would certainly check out local meetups and user groups if you can! It's one of the best ways to get better with these technologies, and you'll probably meet some great people as a result!&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>security</category>
      <category>azure</category>
    </item>
  </channel>
</rss>
