Hey ops people, you’re doing it wrong. (But we can fix it!)
Hey ops people, you’re doing it wrong. (But we can fix it!)
One of the biggest push backs that we have when talking to operations teams about Nitric is a version of, “yeah…Nitric is amazing and all, but we really don’t want our devs in control of infrastructure.” But let me tell you a little secret. Your devs already ARE in control of the infra every time they code the line “import boto3”. The ops teams are just there post PR to sort out all the silly stuff the dev thought they needed to get their application deployed.
So ops teams are really just firefighters rather than cooperative team members. Nitric believes that the best practices should be put in place BEFORE the application development rather than fixing it afterwards. How many times has the project architect, in sync with the dev team and ops folks, defined an architecture and guardrails for security only to have that carefully coordinated ideal fall away as a mythic story buried in the mists of time and agile slide presentations? That stops now.
Using Nitric’s project structure and .yaml file, which is definable and customizable, to anchor that project architecture ahead of development keeps the tensions low, cooperation high and efficiency on point. You can deploy directly to the cloud via Pulumi, or build IaC in Terraform to use with existing security and CI/CD tools. Everyone’s happy. Dogs and cats, living together in harmony.
Let’s take a quick look at how Nitric structures projects, the ideas behind the .yaml definitions and why it’s better than using a cloud provider's SDK directly in the application code.
Stop Playing YAML Tetris
Nitric projects are simple. No rigid folder structures or complex boilerplate. Just a nitric.yaml
file at the root of your project, telling Nitric where your code lives and how to run it. Inside that file, you'll define your services – the entry points to your application.
name: my-awesome-projectservices:- match: services/*.pystart: uvicorn $SERVICE_PATH:app
Each service gets packaged into its own container, keeping things neat, tidy, and scalable. You can even customize how those containers are built with custom Dockerfiles if needed (more on that in the docs!).
The .yaml File: Your Project's Blueprint
The nitric.yaml
file isn't just about finding your services. It's also where you, the magnificent ops guru the operations lead, define the structure and behavior of your project. Think of it as a blueprint, establishing the rules of engagement for your developers. This is where you specify compute resource limits, environment variables, and other configurations that should apply across the project.
config:default:lambda:memory: 512timeout: 15image-processor:lambda:memory: 4096timeout: 300
You can even create custom types of services with different resource requirements. Need a service with more memory or a longer timeout? Define a new type in your nitric.yaml
, then let your developers reference it in their code when requesting resources. No more ad-hoc resource requests or bling-bling surprises on your cloud bill.
The boto3 Bombshell
Now, let's talk about why ditching direct AWS SDK calls (that boto3
import) is crucial for maintaining a secure and well-managed cloud environment.
Imagine a developer needs to store images in S3. With the AWS SDK they might do this directly in their Python code:
import boto3s3 = boto3.client('s3')def upload_image(image_bytes, bucket_name, image_key):s3.put_object(Bucket=bucket_name, Key=image_key, Body=image_bytes)
Looks simple enough, right? But where does that bucket_name
come from? An environment variable? Hardcoded? And what about the IAM role attached to this function? Does it have the s3:PutObject
permission for all buckets or just the ones it should? It's all implicit and scattered, a recipe for disaster.
One misplaced wildcard (*
) in an IAM policy and suddenly that image upload function can write to any S3 bucket in your account. Not ideal and commence the finger pointing.
Nitric lets developers declare their intent, then securely configures the necessary resources and permissions:
from nitric.resources import bucketimage_bucket = bucket("images").allow("write")async def upload_image(image_bytes, image_key):await image_bucket.file(image_key).write(image_bytes)
The difference? No messy IAM policies or environment variables. Nitric's allow()
method explicitly states the function's storage requirements and it only needs to put files into the image bucket. So if that function gets compromised then the attacker can only put files into the image
bucket.
The Lambda Lottery
Similar problems arise with compute. A developer wants to run a background task. Using the AWS SDK directly, they'd define a Lambda function and configure its resource limits in a CloudFormation template or Serverless Framework config:
Resources:MyFunction:Type: AWS::Serverless::FunctionProperties:MemorySize: 1024 # Is this enough? Too much? Who knows!Timeout: 60 # Time bomb ticking...
This approach leads to inconsistent resource allocation, functions that time out unexpectedly, and more head-scratching when things go wrong.
Nitric, on the other hand, brings this configuration into the codebase, ensuring developers set appropriate resource limits in a controlled manner.
from nitric.resources import schedulefrom nitric.application import Nitric@schedule("my-schedule").every("1 minute")async def scheduled_task(ctx):# ...passNitric.run()
This not only improves consistency, but it also makes resource usage clear, auditable and easy to update without messing around with cloud-specific YAML or JSON. Nitric Nirvana: Security and Speed
Nitric helps ops teams establish secure defaults and guide developers toward best practices without sacrificing speed or flexibility. It's time to move beyond reactive firefighting and embrace a proactive approach to cloud security. Check out the Nitric docs to learn more and start building secure, scalable serverless apps today!
Checkout the latest posts
Cloud SDKs Can Chain You Down
With the right level of abstraction over cloud resources, we can separate the responsibilities and concerns of developers and operations teams.
Polyglot projects made easy with Nitric
Nitric makes building cloud applications in multiple languages a breeze
Nitric adds Deno 2 support
Building applications with Deno 2 and Nitric
Get the most out of Nitric
Ship your first app faster with Next-gen infrastructure automation