<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Manan Gandhi</title>
    <description>The latest articles on DEV Community by Manan Gandhi (@manangandhi1810).</description>
    <link>https://dev.to/manangandhi1810</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%2F727244%2F7fcb599c-386d-4c0d-b4ee-8a5de84da1de.jpeg</url>
      <title>DEV Community: Manan Gandhi</title>
      <link>https://dev.to/manangandhi1810</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/manangandhi1810"/>
    <language>en</language>
    <item>
      <title>DockerSensei - The Disciplined Approach to Container Security and Access</title>
      <dc:creator>Manan Gandhi</dc:creator>
      <pubDate>Mon, 05 May 2025 06:31:03 +0000</pubDate>
      <link>https://dev.to/manangandhi1810/dockersensei-master-your-containers-mn9</link>
      <guid>https://dev.to/manangandhi1810/dockersensei-master-your-containers-mn9</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/permit_io"&gt;Permit.io Authorization Challenge&lt;/a&gt;: Permissions Redefined&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What We Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;DockerSensei&lt;/strong&gt; is a platform designed to bring robust and secure management to your Docker containers. It tackles the challenge of providing fine-grained access control over container operations, ensuring that only authorized users can perform specific actions such as spawning containers, starting/stopping containers, viewing logs and executing shell commands. By integrating Permit.io, DockerSensei leverages Role-Based Access Control (RBAC) to offer a scalable and auditable permission management system for your containerized environment.&lt;/p&gt;

&lt;p&gt;Imagine a scenario where you have multiple teams working with different sets of containers. DockerSensei allows you to define roles like "Developer" who can manage the application containers, "Tester" who can only view logs for debugging, and "Admin" who has full control over the entire Docker infrastructure. This eliminates the "all or nothing" approach often associated with basic Docker management and enhances security significantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;The application is hosted at: &lt;a href="https://dockersensei.rushabhjaveri.com" rel="noopener noreferrer"&gt;https://dockersensei.rushabhjaveri.com&lt;/a&gt;. The application is in Demo Mode, thus there can be only 10 containers at maximum at any given time on the server, to save on resources.&lt;br&gt;
You can use the following credentials to explore the application:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Admin: &lt;a href="mailto:admin@dockersensei.example.com"&gt;admin@dockersensei.example.com&lt;/a&gt; / password: 2025DEVChallenge&lt;/li&gt;
&lt;li&gt;Developer: &lt;a href="mailto:developer@dockersensei.example.com"&gt;developer@dockersensei.example.com&lt;/a&gt; / password: 2025DEVChallenge&lt;/li&gt;
&lt;li&gt;Tester: &lt;a href="mailto:tester@dockersensei.example.com"&gt;tester@dockersensei.example.com&lt;/a&gt; / password: 2025DEVChallenge&lt;/li&gt;
&lt;li&gt;New User (Viewer): &lt;a href="mailto:newuser@dockersensei.example.com"&gt;newuser@dockersensei.example.com&lt;/a&gt; / password: 2025DEVChallenge&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These credentials may give unrestricted access to the entire system, please use them responsibly.&lt;/p&gt;

&lt;p&gt;Screenshots:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Listing Containers
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiezms4s76ife1nqgfiw1.png" alt="Listing Containers" width="800" height="138"&gt;
&lt;/li&gt;
&lt;li&gt;Container Management (Admin)
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Futeunjonkd462su0f4wc.png" alt="Container Management (Admin)" width="800" height="327"&gt;
&lt;/li&gt;
&lt;li&gt;Container Management (Tester)
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm1n0zn5yr88ngohjczsq.png" alt="Container Management (Tester)" width="800" height="326"&gt;
&lt;/li&gt;
&lt;li&gt;Container Management (Developer)
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy4146vpwdx16eb1nejnp.png" alt="Container Management (Developer)" width="800" height="329"&gt;
&lt;/li&gt;
&lt;li&gt;User Management Dashboard (Admin)
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdscr65uzulrfkqlcng37.png" alt="User Management Dashboard" width="800" height="293"&gt;
&lt;/li&gt;
&lt;li&gt;Audit Logs (Admin)
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4h5hi81v4oo7y8r47be0.png" alt="Audit Logs" width="800" height="287"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(In the Container management images, notice that the actions which the user does not have access to, such as start/stop are disabled.)&lt;/p&gt;
&lt;h2&gt;
  
  
  Project Repo
&lt;/h2&gt;

&lt;p&gt;The GitHub repository URL is - &lt;a href="https://github.com/MananGandhi1810/devto-permit-hackathon" rel="noopener noreferrer"&gt;https://github.com/MananGandhi1810/devto-permit-hackathon&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Setup Steps
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Clone the repository:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/MananGandhi1810/devto-permit-hackathon.git dockersensei
&lt;span class="nb"&gt;cd &lt;/span&gt;dockersensei
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Set up the environment variables:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Copy `.env.example` to `.env` in both `backend` and `frontend` directories.
- Fill in the required values, including Permit.io credentials.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Start the services using Docker Compose:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Access the application:

&lt;ul&gt;
&lt;li&gt;Frontend: &lt;a href="http://localhost:8000" rel="noopener noreferrer"&gt;http://localhost:8000&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Backend API: &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Our Journey
&lt;/h2&gt;

&lt;p&gt;Building DockerSensei was an insightful journey into the world of container management and the power of externalized authorization. Initially, we considered implementing a custom permission system directly within the Node.js backend. However, as the requirements for fine-grained control and the need for scalability grew, it became clear that a dedicated solution like Permit.io would be far more efficient and secure.&lt;/p&gt;

&lt;p&gt;One of the main challenges we faced was understanding the nuances of RBAC and how to effectively model the different user roles and their corresponding permissions in the context of Docker container operations. Permit.io's documentation and CLI proved invaluable in navigating this learning curve.&lt;/p&gt;

&lt;p&gt;Integrating Dockerode with the backend to interact with the Docker daemon also presented some interesting challenges, particularly around handling asynchronous operations and streaming container logs in real-time to the frontend. We used Socket.IO to establish real-time connections for the exec and logs functionalities, allowing users to interact with running containers and view log output in near real-time.&lt;/p&gt;

&lt;p&gt;On the frontend, using React with Shadcn/UI and Tailwind CSS allowed for rapid development of a clean and responsive user interface.&lt;/p&gt;

&lt;p&gt;We have hosted our frontend on Vercel, and the backend on a Virtual Machine from Digital Ocean. The backend is served via a Caddy reverse proxy, allowing us to connect our domain &lt;a href="https://dockersensei.rushabhjaveri.com" rel="noopener noreferrer"&gt;https://dockersensei.rushabhjaveri.com/&lt;/a&gt; easily.&lt;/p&gt;

&lt;p&gt;Throughout this process, we learned the importance of separating concerns – keeping the core application logic distinct from the authorization layer. This not only improves security but also makes the application more maintainable and adaptable to future changes in permission requirements.&lt;/p&gt;

&lt;p&gt;Container management systems are the backbone of modern software deployment, running mission-critical applications that handle sensitive data and provide essential services. In such environments, robust access control is not just a best practice, but a necessity, because of the following reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Security:&lt;/strong&gt; Unauthorized access can lead to severe security breaches, including data leaks and service disruptions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compliance:&lt;/strong&gt; Many industries have strict rules (e.g., GDPR, HIPAA) about data access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operational Integrity:&lt;/strong&gt; Access control prevents accidental or intentional misconfigurations.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Using Permit.io for Authorization
&lt;/h2&gt;

&lt;p&gt;Permit.io is at the heart of DockerSensei's access control mechanism. We leveraged the Permit.io CLI and backend SDK to implement the following:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Defining Roles and Permissions:&lt;/strong&gt; Using the Permit.io dashboard, we defined the four predefined roles (Admin, Developer, Tester, Viewer) and their associated permissions. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Admin role has permissions to start, stop, restart, logs, exec, and list all containers, as well as assign roles to the users and view audit logs.&lt;/li&gt;
&lt;li&gt;The Developer role can start, stop, restart, exec, logs, and list containers.&lt;/li&gt;
&lt;li&gt;The Tester role can only logs and list containers.&lt;/li&gt;
&lt;li&gt;The Viewer role can list containers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Implementing Permission Checks in the Backend:&lt;/strong&gt; In the Node.js backend, before executing any container-related action, we used the Permit.io SDK to check if the currently authenticated user has the necessary permission for that specific action. For instance, before allowing a user to stop a container, the backend would perform a check like:&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;const&lt;/span&gt; &lt;span class="nx"&gt;accessControl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &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;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isPermitted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;check&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;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resource&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isPermitted&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No permission&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&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="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Permit.io is used here as middleware in Express.js to check for authorization&lt;/span&gt;
&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/:id/restart&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;checkAuth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Authentication middleware (verifies the user's identity)&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;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="nf"&gt;accessControl&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;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// Authorization middleware (uses Permit.io)&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;restart&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Container&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;restartContainerHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// The actual handler function for restarting the container&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Dynamic Role Assignments:&lt;/strong&gt; The Admin dashboard allows administrators to assign roles to users. When a role is assigned or revoked, the backend interacts with the Permit.io API to update the user's permissions in real-time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Audit Logging:&lt;/strong&gt; While Permit.io provides its own audit logs, DockerSensei also maintains internal audit logs, recording user actions and the outcome of permission checks, providing an additional layer of traceability.&lt;/p&gt;

&lt;p&gt;By using Permit.io, DockerSensei achieves a robust, scalable, and easily manageable authorization system, freeing up development time that would otherwise be spent on building and maintaining a custom RBAC solution. The Permit.io CLI made it straightforward to define and manage the authorization model, and the SDK seamlessly integrated with the backend logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RBAC Policy:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Admin&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuysggs363dighixbsnjd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuysggs363dighixbsnjd.png" alt="Admin" width="674" height="1218"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Developer&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzy7keugelwifonj9get9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzy7keugelwifonj9get9.png" alt="Developer" width="662" height="1200"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tester&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ce6v38zqufgwtjfitt5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ce6v38zqufgwtjfitt5.png" alt="Tester" width="646" height="1184"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Viewer&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh4lgi9lgifc1b8q8i3yq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh4lgi9lgifc1b8q8i3yq.png" alt="Viewer" width="660" height="1192"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The DockerSensei team consists of &lt;strong&gt;Manan Gandhi (&lt;a href="https://dev.to/manan"&gt;manangandhi1810&lt;/a&gt;)&lt;/strong&gt; and &lt;strong&gt;Rushabh Javeri (&lt;a href="https://dev.to/rushabh"&gt;rushabh&lt;/a&gt;)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Huge thanks to Dev.to and Permit.io for providing us with the opportunity of participating in this hackathon.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>permitchallenge</category>
      <category>webdev</category>
      <category>security</category>
    </item>
  </channel>
</rss>
