What is an instance profile - how EC2 gets permissions
An instance profile is the small container AWS uses to physically hand an IAM role to an EC2 instance — without it, the role you created has nowhere to attach, and the instance has no way to prove who it is when it asks for temporary credentials. The part almost nobody tells you: every EC2 instance you have ever launched already had an identity of its own, called the instance identity role, whether you attached a profile or not.
Jake runs a phone repair and resale shop, and about two years ago he built a small internal tool on an EC2 instance that photographs incoming trade-in phones and drops the images into an S3 bucket for his inventory system. It worked. It also had his personal AWS access key and secret key sitting in a plain text config file on that instance, because a contractor told him "just put your keys in there, it's the fastest way." That instance got backed up to a public snapshot by accident eight months later. Nobody stole anything — this time — but when Jake found out what could have happened, he called his mentor Ethan in a panic.
"So somebody could have taken that file and logged in as you? Not just gotten into the bucket — into my whole AWS account?" Jake asked.
"Yes," Ethan said. "Anyone with your secret key can do anything your IAM user is allowed to do, from any computer on earth, until you notice and rotate it. That's exactly the problem instance profiles exist to solve. You were doing the one thing AWS specifically built a feature to stop people from doing."
That's what this whole article is about: how an EC2 instance is supposed to get permission to talk to other AWS services — S3, DynamoDB, Secrets Manager, whatever your application needs — without anybody ever typing an access key into a config file. The mechanism is an IAM role (a set of permissions that can be "worn" temporarily) delivered to the instance through an instance profile (the container that makes that handoff possible). They sound like the same thing. They are not, and that one distinction is where most of the confusion in this topic comes from.
Why EC2 needs this extra step at all
To understand why instance profiles exist, you have to understand the problem they replaced. An application running on an EC2 instance needs to sign its requests to other AWS services with credentials — an access key and a secret key. Before roles existed, the only way to get those credentials onto the instance was to physically put them there: bake them into an AMI, drop them in a config file, pass them in as user data at launch. Every one of those approaches has the same fatal flaw. The credentials are long-lived (they don't expire on their own), and they are sitting somewhere a person, a misconfigured backup, a leaked GitHub repo, or a compromised process on the box could read them.
An IAM role fixes the "long-lived" half of that problem. A role isn't a user and it doesn't have a permanent password or access key of its own — it's a set of permissions that something else can temporarily "assume," the way a substitute teacher wears a name badge for the day without ever getting the regular teacher's house key. When an EC2 instance assumes a role, AWS hands it a temporary access key, secret key, and session token that are only good for a few hours and rotate automatically.
But a role by itself has nowhere to live on a virtual machine. Amazon Web Services designed the instance profile as the physical connector — the socket the role plugs into so an EC2 instance specifically can carry it. Without that container, "attach a role to an instance" isn't actually an operation that exists in the EC2 API. You attach an instance profile. The role just happens to be riding inside it.
♂️ Jake's Reality Check
"Okay, but every time I've done this in the console, I picked a role. I never saw an 'instance profile' anywhere. Where was it hiding?"
It was there — the console just built it for you and hid the seam. When you create a role through the IAM console and it's meant for EC2, the console automatically creates an instance profile with the exact same name and quietly puts the role inside it. The dropdown you picked from in the EC2 launch wizard, labeled "IAM instance profile" or sometimes just "IAM role," is actually listing instance profile names, not role names. If you've only ever used the console, you have been using instance profiles the whole time without knowing the word.
Instance profile vs. IAM role — the difference nobody explains clearly
Here's the plainest way to say it: the role is the permissions. The instance profile is the delivery box. You write policies (JSON documents describing what a role is and isn't allowed to do — think of a policy as a written permission slip) and attach them to the role. You put the role inside an instance profile. You attach the instance profile — not the role — to the EC2 instance.
Ethan likes to describe it to Jake this way: "Think about the badge you'd give a temp worker at your shop. The role is the list of doors that badge opens — the stockroom, the register, not the safe. The instance profile is the actual plastic badge holder clipped to their shirt. You can write the world's best access list, but if there's no badge holder to clip it to, the temp worker is standing there with a piece of paper in their pocket that the door scanner can't read."
This distinction matters for one very practical reason: it changes depending on how you create the role. AWS's own documentation on IAM roles for EC2 explains it directly. If you create the role using the AWS Management Console, the instance profile is created for you automatically, with the same name as the role, and you'll likely never need to think about it again. If you create the role using the AWS CLI, an SDK, or the API — which includes most Infrastructure as Code tools — you must create the role and the instance profile as two separate steps, and you're allowed to give them different names. That second path is where almost every "why can't I find my role" support ticket comes from, and we'll cover it in detail in the troubleshooting section below.
| Thing | What it actually is | Can you attach it to an EC2 instance directly? |
|---|---|---|
| IAM role | A set of permissions plus a trust policy saying who's allowed to assume it (in this case, ec2.amazonaws.com) |
No — has no attachment point of its own for EC2 |
| Instance profile | A container holding exactly one role, built specifically so EC2 can pass that role to a virtual machine | Yes — this is the only thing EC2 actually attaches |
| Access key / secret key | A long-lived credential pair tied to an IAM user, not a role | Can be placed on an instance manually, but it's exactly what instance profiles exist to replace |
One more fact worth locking in early, because it trips people up constantly later: an instance profile can hold only one IAM role. That limit cannot be raised, no matter what account settings you change. A role, on the other hand, can be placed inside many different instance profiles at once. So the relationship is one role can go into many profiles, but each profile can only ever carry one role at a time.
How the credential handoff actually works
Once an instance profile with a role inside it is attached to a running instance, here's what happens mechanically. The instance can reach a special address, 169.254.169.254, which is the Instance Metadata Service, or IMDS — a small internal-only web server that every EC2 instance can talk to about itself. It's not on the public internet; nothing outside the instance's own network path can reach it. Through IMDS, anything running on the instance can ask "who am I, and what can I do?" and get an answer without you ever configuring a username or password.
The specific address AWS's documentation gives is iam/security-credentials/role-name. Hit that path with the right headers and you get back a small JSON document containing a temporary access key ID, a temporary secret access key, and a session token — the same three pieces of information a permanent credential pair would have, except these expire. AWS's own guide is explicit that it rotates these automatically and makes the new set available at least five minutes before the old ones expire, so a well-behaved application never actually notices the swap happening.
In practice you almost never touch this by hand. The AWS CLI and every official AWS SDK are already written to check IMDS for these credentials automatically, so a script running on an EC2 instance with an attached instance profile just works — no configuration file, no environment variable, no key to lose. That "it just works" quality is, honestly, the entire point of the feature.
What changed: IMDSv1 to IMDSv2
- Before: any process on the instance could send a plain
GETrequest to169.254.169.254and read the role's credentials back — no proof of intent required. - Now: AWS's documentation shows the recommended method (IMDSv2) requires you to first
PUTa request tohttp://169.254.169.254/latest/api/tokento receive a short-lived session token, then include that token as a header on every metadata request. - What that means for you: if a script you copied from an old tutorial gets a permission or connection error reading instance metadata, that script is almost certainly written for the older method and needs the token step added.
Why does that token step matter enough for AWS to add it? It closes a class of attacks where some unrelated piece of software on the instance — a badly configured proxy, a vulnerable web app that can be tricked into fetching an arbitrary URL — gets tricked into fetching the metadata address on the attacker's behalf and handing back the role's live credentials. Requiring a token first means a simple "make this server fetch a URL for me" trick isn't enough on its own; the token request has to happen too, from the instance itself. It's a small extra step that closes a real door.
| Step | Linux command | What it gets you |
|---|---|---|
| 1. Request a token | curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" |
A session token good for up to 6 hours (21,600 seconds) in this example |
| 2. Ask who the role is | curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/ |
The name of the role in the attached instance profile |
| 3. Retrieve credentials | curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/role-name |
A JSON block with the temporary access key, secret key, and session token |
You will rarely type these commands for real work, but running them once — from inside an instance you already own, purely to see the shape of what your application is doing behind the scenes — is a genuinely useful way to demystify the whole system. Jake did exactly this after his scare with the hardcoded keys, and said it was the first time the concept actually "clicked" for him.
Creating an instance profile through the console (the easy path)
If you're working in the AWS Management Console, you genuinely don't need to think about the word "instance profile" at any point, which is exactly why so many people have never heard the term until something breaks. Here's the sequence, either during a new instance launch or afterward.
- Open the EC2 console, choose Launch instance, and configure your AMI, instance type, and network settings as usual.
- Expand Advanced details and find the IAM instance profile field.
- If you already have a role you want to use, select it from the dropdown — remember, this list is actually instance profile names.
- If you don't have one yet, choose Create new IAM role. This opens an inline form where you name the role, attach the AWS-managed or custom policies it needs (for example,
AmazonS3ReadOnlyAccessif the instance only needs to read from a bucket), and review the trust policy that letsec2.amazonaws.comassume it. - Choose Create role. The newly created role is automatically selected and, crucially, an instance profile with the identical name has already been created behind the scenes.
- Finish launching the instance as normal.
If the instance already exists, you don't have to relaunch it. From the EC2 console's Instances list, select the instance, choose Actions → Security → Modify IAM role, pick the instance profile from the dropdown, and choose Update IAM role. This works whether the instance is running or stopped — you do not need to shut it down first, which surprises a lot of people who assume permissions changes always require a reboot.
✅ Why this is the one to use for a single instance
For a one-off instance or a small handful of servers you manage by hand, the console path is genuinely the right call — not just the easy one. It removes the entire "did I remember to create the instance profile separately" failure mode, because AWS does that step for you every time. Save the CLI and Infrastructure-as-Code paths below for fleets, automation, and repeatable deployments, where doing it by hand in a browser doesn't scale.
Creating one by hand with the CLI, an SDK, or CloudFormation
This is the path where the console's convenience disappears and you have to do both steps — create the role, then create and populate the instance profile — yourself. Skip either one and nothing will work, and the error you get won't clearly say "you forgot the instance profile."
- Create the role and its trust policy (the JSON document allowing
ec2.amazonaws.comto assume it) withaws iam create-role. - Attach whatever permission policies the application needs, using
aws iam attach-role-policyoraws iam put-role-policyfor a custom inline policy. - Create the instance profile itself:
aws iam create-instance-profile --instance-profile-name Webserver. - Put the role inside it:
aws iam add-role-to-instance-profile --role-name S3Access --instance-profile-name Webserver. This command produces no output on success — that's normal, not a sign it failed. - Attach the finished instance profile to a running or stopped instance with
aws ec2 associate-iam-instance-profile, or specify it at launch time withaws ec2 run-instances.
Notice that in step 3 and 4, the instance profile is named Webserver and the role is named S3Access — deliberately different, straight from AWS's own CLI documentation example. That's completely legal and common when you're scripting this, but it's also exactly the setup that makes people go looking for "S3Access" in the EC2 console dropdown and come up empty, because the dropdown lists Webserver, not S3Access.
If you manage infrastructure with CloudFormation, the equivalent resource is AWS::IAM::InstanceProfile, and its Roles property takes an array of role names — but AWS's own CloudFormation reference is specific that only one role can actually be assigned to an EC2 instance at a time, and all applications running on that instance share that single role's permissions. A minimal example looks like this:
Resources:
MyInstanceProfile:
Type: "AWS::IAM::InstanceProfile"
Properties:
Path: "/"
Roles:
- Ref: "MyRole"
The Ref function here returns the instance profile's name, and if you need the full ARN elsewhere in the same template, Fn::GetAtt with the attribute Arn will give it to you. Either the name or the ARN can be used when you reference the instance profile from an AWS::EC2::Instance or AWS::EC2::LaunchTemplate resource.
Attaching, replacing, and removing a role on an instance that already exists
A question that comes up constantly: "I launched this instance months ago without a role. Can I add one now without starting over?" Yes, and AWS's documentation confirms this works on both running and stopped instances. You are never locked into whatever you picked at launch.
What you cannot do is attach a second instance profile alongside the first. An instance can only ever have one instance profile attached at a time, which — since a profile only holds one role — means an EC2 instance effectively has exactly one role's worth of permissions in force at any given moment. If your application needs permissions from two different teams' policies, the fix is to combine those permissions into a single role, not to try attaching two profiles.
To swap the role, you don't remove the old profile and then add a new one as two separate actions in the console — you use Modify IAM role, select the new instance profile, and AWS handles replacing the association for you. Behind the scenes, this is calling the API operation ReplaceIamInstanceProfileAssociation, which is worth knowing because if you're scripting this rather than clicking through the console, that's the exact call to reach for.
⚠️ What removing a role actually breaks
AWS's own guidance says plainly: don't remove a role from an instance profile if you can avoid it, because there is a delay of up to one hour before that change is fully visible everywhere in AWS. During that window your application might keep using stale, cached credentials, or suddenly find itself with no valid credentials at all, depending on exactly when it last refreshed. If you need the change to take effect immediately rather than waiting up to an hour, you have two options: disassociate the instance profile and then re-associate a new one (two separate API calls), or simply stop the instance and start it again. A reboot alone isn't enough — it has to be a full stop and start.
The permissions you personally need to do any of this
Here's a detail that catches experienced engineers off guard the first time they hand this task off to a junior teammate or automate it in a pipeline: attaching a role to an instance is not covered by ordinary EC2 permissions. Because you're effectively handing a set of permissions to a piece of infrastructure, IAM requires an extra, separate permission called iam:PassRole — the caller has to be explicitly allowed to "pass" that specific role to something else.
AWS's EC2 documentation lists the full set of API actions your own IAM user or role needs, depending on what you're trying to do:
| Permission | Needed for |
|---|---|
iam:PassRole | Handing any role over to an EC2 instance at all — the single most-forgotten permission in this whole topic |
ec2:AssociateIamInstanceProfile | Attaching a profile to a running or stopped instance |
ec2:DisassociateIamInstanceProfile | Removing one |
ec2:ReplaceIamInstanceProfileAssociation | Swapping one profile for another on an existing instance |
iam:ListInstanceProfiles | Only needed for console access, so the dropdown can populate |
AWS's documentation also flags a specific trap: if you write your iam:PassRole permission with a wildcard resource — a "Resource": "*" that means "any role at all" — you've just given that user or automation the ability to hand your account's most powerful roles to an EC2 instance, not just the one they were supposed to use. The documented best practice is to scope iam:PassRole down to the specific ARNs of the roles you actually intend people to pass, something like arn:aws:iam::123456789012:role/DevTeam* rather than a bare asterisk.
What breaks, and what it actually means
This is the part most articles skip, and it's the part people are actually searching for at 11pm with a broken deployment. Every symptom below is documented behavior, not a guess — AWS keeps a troubleshooting page specifically for IAM-and-EC2 problems, and every row below traces back to it.
| Symptom | Most likely cause | Fix |
|---|---|---|
| Role doesn't appear in the EC2 launch wizard's dropdown | You created the role via CLI/API and never created (or never populated) a matching instance profile — or your own user lacks ListInstanceProfiles |
Create the instance profile, add the role to it with add-role-to-instance-profile, and check your own permissions |
| Credentials on the instance are for the wrong role | You recently swapped the role and the instance hasn't refreshed yet | Wait for the next scheduled refresh, or disassociate/re-associate the profile, or stop and start the instance |
AccessDenied calling AddRoleToInstanceProfile |
Your IAM user lacks iam:AddRoleToInstanceProfile scoped to that profile's ARN |
Grant that permission on the specific instance-profile resource |
AccessDenied launching an instance with a role |
Missing iam:PassRole on the role's ARN, or an empty instance profile with no role inside it |
Add iam:PassRole for that exact role; call GetInstanceProfile to confirm the profile actually contains a role |
Can't reach iam/security-credentials/ at all |
No instance profile is associated with the instance, or IMDS is blocked by a local firewall rule | Confirm with aws ec2 describe-instances that a profile is attached; test basic IMDS access with the hostname metadata path first |
iam/info shows InstanceProfileNotFound |
The instance profile was deleted after the instance launched, or was deleted and re-created under the same name | Compare the InstanceProfileId from IAM against the IamInstanceProfileId EC2 reports for the instance; attach a valid profile |
| Message: "Instance Profile does not contain a role..." | Someone called RemoveRoleFromInstanceProfile, leaving an empty profile still attached |
Add a role back with AddRoleToInstanceProfile, then force the refresh if you can't wait |
AssumeRoleUnauthorizedAccess in the credentials response |
The role's trust policy doesn't allow ec2.amazonaws.com to assume it |
Update the trust policy to include an Allow statement for the EC2 service principal, then force a refresh |
That last row is worth pausing on, because it's the one that fools people the longest. The permission policy attached to the role can be perfect — every action the application needs, correctly scoped — and the instance will still get nothing, because the trust policy (the part of the role that says who's allowed to wear it) never granted EC2 the right to assume it in the first place. A trust policy that works looks like this, straight from AWS's own troubleshooting guide:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Service": ["ec2.amazonaws.com"] },
"Action": ["sts:AssumeRole"]
}
]
}
If you created your role in the console specifically for EC2, this trust policy was already written for you. If you built the role by hand — say, by copying an existing role's permission policy and forgetting the trust policy came from somewhere else — this is the piece that's easy to lose.
The identity every instance already has, whether you attached anything or not
Here's the fact from the opening of this article, explained properly. AWS's EC2 documentation describes something called the instance identity role — a type of IAM role that every single EC2 instance receives automatically the moment it launches, with no configuration from you at all. It exists regardless of whether you attach an instance profile, and its credentials are always present in instance metadata whether or not any feature is actively using them.
This isn't the role you attach and use for your application's own S3 or DynamoDB calls — it's a separate identity built for AWS services to confirm "yes, this specific request really is coming from this specific instance." According to AWS's documentation, its credentials live at their own IMDS path — /identity-credentials/ec2/security-credentials/ec2-instance — distinct from the iam/security-credentials/ path your attached role uses. Services that currently rely on it include EC2 Instance Connect (to update a Linux instance's host keys), GuardDuty Runtime Monitoring, AWS Systems Manager's default host management, and AWS STS's GetCallerIdentity action, among others documented by AWS.
The ARN format is distinctive too — arn:aws:iam::account-number:assumed-role/aws:ec2-instance/instance-id — and it has no trust policy document and isn't subject to any identity or resource policy you could edit even if you wanted to. It's not a security hole; it can't be used with services that haven't specifically integrated with it. But it's a good reminder that "EC2 identity" is a bigger topic than the one role you consciously attach — the instance has always had some form of built-in identity, and the instance profile you create is layered on top of that, not instead of it.
♂️ Jake's Reality Check
"Wait, so if I never touch instance profiles at all, my server still has some kind of ID card?"
Yes, but it doesn't do anything for your application. That built-in identity role is scoped to a short, specific list of AWS-integrated features — it can't call S3 or DynamoDB on your behalf just because it exists. If your app needs to read a bucket, you still need to create and attach an instance profile the normal way. Think of the instance identity role as the serial number stamped on the machine at the factory, not a set of keys you can use.
Auto Scaling groups, launch templates, and fleets of instances
Everything above assumes one instance you're managing by hand. In practice, once Jake's shop grew and he started running several EC2 instances behind a load balancer, the picture changes slightly, and it's worth covering because "how do I do this for a fleet" is one of the most common follow-up questions.
AWS's Auto Scaling documentation confirms that instances launched inside an Auto Scaling group get their instance profile from the launch template (or the older launch configuration), not from a per-instance setting you configure after the fact. You create the role first, create the instance profile, and then reference that instance profile inside the launch template. Every instance the Auto Scaling group creates from that template — whether there are two of them or two hundred — launches with the same instance profile already attached, with no manual step per instance. This is exactly the scenario where doing this by hand in the console for every new instance would be unworkable, and where the CLI/CloudFormation path from earlier in this article earns its keep.
One consequence worth knowing: because every instance in the group shares the same instance profile, they also share the same permissions. If two workloads on the same Auto Scaling group genuinely need different access levels, that's a sign they belong in separate Auto Scaling groups with separate launch templates and separate roles, not one group trying to serve two purposes.
Doing this safely: least privilege and the mistakes that actually happen
An instance profile isn't automatically "safe" just because it isn't a hardcoded key sitting in a config file. It's safer by default, not safe by default. The permissions attached to that role are still the real boundary, and a role with overly broad permissions attached to a single compromised web server is still a serious problem — the credentials just happen to rotate on their own.
Ethan's advice to Jake, once the panic wore off, was blunt: "Fixing the hardcoded key was step one. Step two is actually looking at what permissions that role has, because right now it probably has way more than your photo tool needs." AWS's own EC2 documentation echoes this directly, recommending you associate least-privilege policies that restrict a role to the specific API calls the application actually requires, rather than reaching for a broad managed policy because it's faster to attach. It also points to IAM Access Analyzer's policy generation feature, which reviews your CloudTrail logs and can generate a tighter policy template based on what a role has genuinely been used for — useful once an application has been running long enough to have a real access pattern to analyze.
A few habits worth building in from day one:
- Name roles and instance profiles the same thing when you create them by hand, even though AWS allows different names — it saves you from the exact "why isn't my role in the dropdown" confusion covered above.
- Scope
iam:PassRoleto specific role ARNs for anyone or anything that's allowed to attach roles to instances, never a bare wildcard. - Treat one instance profile as one job. If an application's needs grow, edit that role's policy rather than reaching for a second, broader role "just in case."
- Confirm you're using IMDSv2's token step in any script you copy from an older tutorial, rather than assuming the plain, tokenless request still works everywhere it used to.
Mistakes beginners make with instance profiles
Beyond the individual failure modes already covered, a handful of conceptual mix-ups show up over and over in support forums and Jake's own group chat with other small shop owners who've started dabbling in AWS:
Treating "role" and "instance profile" as interchangeable in scripts. This works fine right up until you script something that needs the instance profile's own name or ARN specifically — associating a profile with an instance, for example, needs the profile's identifier, not the role's.
"I fought this exact thing for two hours once," Ethan admitted. "I had a script that worked perfectly in the console-created world where the names always matched, and it broke the moment I ran it against a CLI-created setup where they didn't. The error message never once said 'you're passing a role name where a profile name belongs.' It just failed to find anything."
Jake laughed. "So even you get bitten by this."
"Everyone gets bitten by this exactly once," Ethan said. "The trick is making sure it's only once."
Assuming a role change is instant. As covered above, removing a role from a profile carries a documented delay of up to an hour, and even reassociating an entirely new profile isn't guaranteed to be instantaneous — the safest way to force an immediate change is a full stop-and-start of the instance.
Assuming an instance profile can hold a "backup" role. It can't. One role per profile, full stop, and that limit cannot be increased by AWS Support or a service quota request — it's a hard architectural limit, not a soft default.
Forgetting the trust policy exists as a separate document from the permission policy. A role can have flawless permissions and still refuse to work on an EC2 instance if its trust policy never granted the EC2 service permission to assume it in the first place.
Jake's shop has a running joke about this now — any time something inexplicably stops working an hour after somebody swore they'd "already fixed it," the group chat just says "sounds like an instance profile problem," whether AWS is involved or not. It usually isn't. But the shorthand stuck because the lesson underneath it is real: permission changes that look instant from where you're sitting are often still working their way through the system.
Quotas, cost, and tagging
Instance profiles themselves have no price tag — you are never billed for creating one, and there is no per-instance-profile line item on an AWS bill. What you pay for is the underlying compute and any services the role's permissions let the instance interact with, exactly as you would anyway.
There is a limit on how many instance profiles an AWS account can hold, governed by the standard IAM object quotas AWS documents for the account. For the overwhelming majority of setups — even fairly large fleets — this ceiling is far higher than what a normal application architecture would ever need, since Auto Scaling groups reuse a single instance profile across every instance they launch rather than needing one profile per machine. If you're building something unusual enough to approach that ceiling, that's a sign the account structure itself is worth a second look before the quota becomes the actual blocker.
Instance profiles can also be tagged for organization and access control, but only through the AWS CLI or API — the console does not currently offer a way to tag an instance profile directly. If your team uses tags to track cost centers or ownership, that's a detail worth building into your CLI or CloudFormation workflow from the start, since there's no console fallback to catch it later.
Plain-English glossary, for anyone still catching up on the jargon
IAM (Identity and Access Management) is the AWS system that decides who and what is allowed to do what, across your entire account — every user, role, and permission in this article lives inside IAM.
ARN (Amazon Resource Name) is the unique, full address of a specific thing in AWS — like a full street address instead of just a house number, it identifies one exact role or one exact instance profile out of everything in your account, across every region.
Trust policy is the part of a role that answers "who is allowed to wear this badge?" — separate from the permission policy, which answers "what can the badge holder actually do?"
Instance Metadata Service (IMDS) is a small internal web address, 169.254.169.254, that only the instance itself can reach, used for the instance to ask questions about its own configuration and identity.
CLI (Command Line Interface) is the text-based tool for controlling AWS by typing commands instead of clicking through the web console — most of the commands referenced above start with aws.
CloudFormation is AWS's own tool for describing your infrastructure — instances, roles, instance profiles, and more — as a text file (JSON or YAML) that AWS then builds for you automatically, rather than clicking through the console by hand.
Frequently asked questions
What's the actual difference between an IAM role and an instance profile?
The role holds the permissions and the trust policy saying who can use them. The instance profile is the container that physically lets EC2 attach that role to a virtual machine — you attach the profile, never the role directly, when the target is an EC2 instance.
Why does an EC2 instance need an instance profile instead of just using the role directly?
Because roles have no attachment mechanism of their own for EC2 specifically. AWS built the instance profile as that missing connector, so an application on the instance can retrieve the role's temporary credentials automatically from instance metadata.
Can I attach more than one IAM role to a single EC2 instance?
No. An instance profile can contain only one IAM role, and this limit cannot be increased. If an application needs permissions that span more than one existing role, combine those permissions into a single role's policy instead.
Can the same IAM role be used on more than one instance at a time?
Yes. You can only attach one role to a given instance, but that same role can be included in the instance profiles attached to many different instances at once — there's no restriction on reuse across a fleet.
Why can't I find my role in the EC2 console's "IAM role" dropdown?
That dropdown actually lists instance profile names, not role names. If you created your role through the AWS CLI, an SDK, or the API and gave the instance profile a different name — or forgot to create one at all — the role itself won't appear there.
How long does it take for a new instance profile to actually start working?
Attaching a profile to a running or stopped instance generally works right away. Removing or replacing a role inside a profile is the slower case — AWS documents a delay of up to an hour before that specific change is fully visible, unless you force it with a disassociate/associate cycle or a full stop-and-start of the instance.
What happens if I remove the role from an instance profile while the instance keeps running?
The instance profile stays attached, but it's now empty. Applications trying to fetch credentials get an error indicating the profile doesn't contain a role, and any credentials already cached on the instance will eventually expire without a replacement until you add a role back.
Is it okay to just put an AWS access key and secret key on the instance instead?
It works technically, but it recreates the exact long-lived-credential exposure that instance profiles were designed to remove — a leaked key doesn't expire on its own, and it can be used from anywhere, not just from your instance. An instance profile's credentials are temporary, rotate automatically, and never need to be typed into a file at all.
How does an application on the instance actually retrieve its temporary credentials?
It queries the Instance Metadata Service at 169.254.169.254, at the path iam/security-credentials/ followed by the role's name. The AWS CLI and official SDKs already do this automatically, so most applications never call it directly.
What is IMDSv2 and does it change how instance profiles work?
IMDSv2 is the current, session-token-based method of talking to instance metadata. It requires requesting a short-lived token first and including it on every subsequent request, closing off attacks where an unrelated process gets tricked into fetching your role's credentials with a plain request. It doesn't change what an instance profile is — only how you ask for the credentials it delivers.
Can I swap the IAM role on a running instance without stopping it first?
Yes — attaching, replacing, or detaching an instance profile is supported on both running and stopped instances. Stopping and starting is only necessary if you need a change to take effect immediately rather than waiting for the normal refresh cycle.
Is there a limit on how many instance profiles I can create?
Yes, governed by the standard IAM object quotas for your account. For nearly every real-world setup this ceiling is well beyond what's needed, especially since Auto Scaling groups reuse one instance profile across every instance they launch rather than requiring a new profile per machine.
Do instance profiles cost anything to use?
No. There's no charge for creating or attaching an instance profile itself. You only pay for the underlying EC2 instance and any AWS services the attached role's permissions actually let it use.
What permissions does my own IAM user need to attach a role to an instance?
iam:PassRole on the specific role's ARN is the one people forget most, alongside ec2:AssociateIamInstanceProfile, ec2:DisassociateIamInstanceProfile, and ec2:ReplaceIamInstanceProfileAssociation depending on the action. Console access additionally requires iam:ListInstanceProfiles so the dropdown can populate.
What is an "instance identity role," and is that the same thing as my instance profile?
No — it's a separate, automatically created identity every EC2 instance gets at launch regardless of whether you attach an instance profile at all. Its credentials live at a different metadata path and are only usable by a specific, documented list of AWS-integrated features, not by your own application code.
Can instances in an Auto Scaling group use an instance profile the same way?
Yes, but you configure it once in the launch template (or launch configuration) rather than per instance. Every instance the group launches from that template automatically gets the same instance profile, and therefore the same permissions, attached at launch.
Revision note. Written September 2026, covering current AWS documentation on IAM roles, instance profiles, IMDSv2, and instance identity roles for Amazon EC2. This will need a fresh look if AWS changes how instance identity roles are exposed, adds a way to attach more than one role per profile, or shifts IMDS defaults further. If you've been staring at a role that "should just work" and doesn't, you're not missing something obvious — this system has more quiet edge cases than it looks like at first glance, and that's exactly why we wrote all of them down in one place.
π‘ Recommended AWS Foundations Reading
Master the core building blocks of AWS infrastructure, networking, and security:
- πΊ️ Regions vs. Availability Zones — The physical map that fixes half of your latency and redundancy bugs.
- π Decoding AWS ARNs — How to read the exact address syntax for any resource across accounts and regions.
- π‘️ Shared Responsibility Model — Who fixes what when an AWS service fails or leaks.
- π Public vs. Private Subnets — Visualizing traffic flow and network isolation in a VPC.
- πͺ Internet Gateway vs. NAT Gateway — Outbound internet routing without hidden cost surprises.
- π§± AWS Security Groups — Stateful firewall rules explained in plain English.
- π Service-Linked Roles — The permissions AWS automatically creates and manages for you.
- π₯️ EC2 Instance Profiles — How EC2 instances access services without hardcoded access keys.
- π¨ Root User vs. IAM User — Why you should lock away root credentials immediately.
- π AWS MFA Setup Guide — Clear the console nagging banner and secure your account in 3 minutes.